<?php

namespace App\V3\V3_2_7\Services;

use App\Services\CommonService;
use App\V3\V3_2_7\Models\BarterModel;
use App\V3\V3_2_7\Models\DataFieldPowerAdminModel;
use App\V3\V3_2_7\Models\InStorageLogModel;
use App\V3\V3_2_7\Models\LoginModel;
use App\V3\V3_2_7\Models\LogInStorageModel;
use App\V3\V3_2_7\Models\LogOutPackageModel;
use App\V3\V3_2_7\Models\LogOutStorageModel;
use App\V3\V3_2_7\Models\LogPackageContentModel;
use App\V3\V3_2_7\Models\LogPackageModel;
use App\V3\V3_2_7\Models\MaterielClassModel;
use App\V3\V3_2_7\Models\MaterielModel;
use App\V3\V3_2_7\Models\MaterielProductContentModel;
use App\V3\V3_2_7\Models\OperMainAccountModel;
use App\V3\V3_2_7\Models\PackageModel;
use App\V3\V3_2_7\Models\ProductOrderModel;
use App\V3\V3_2_7\Models\SalesReturnModel;
use App\V3\V3_2_7\Models\SellModel;
use App\V3\V3_2_7\Models\SerialNumberModel;
use App\V3\V3_2_7\Models\StorageBatchModel;
use App\V3\V3_2_7\Models\StorageManageModel;
use App\V3\V3_2_7\Models\StorageModel;
use App\V3\V3_2_7\Models\SupplierCustomerModel;
use App\V3\V3_2_7\Models\UpdInOutLogModel;
use App\V3\V3_2_7\Models\UserModel;
use Exception;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use App\V3\V3_2_7\Models\MaterielSerialNumberModel;
use Illuminate\Support\Facades\Log;
use App\V3\V3_2_7\Models\OverflowBreakageModel;
use App\V3\V3_2_7\Models\MaterielTypeModel;

class LogService
{
    //操作记录详细
    static public function detail($data)
    {
        switch ($data['type']) {
            case 0:
                $result = self::logInStorageDetail($data);
                break;
            case 1:
                $result = self::logOutstorageDetail($data);
                break;
        }

        return $result;
    }

    //删除操作记录
    static public function delImportstorageLog($data)
    {
        switch ($data['type']) {
            case 0:
                unset($data['type']);
                $result = self::delImportLogInStorage($data);
                break;
            case 1:
                unset($data['type']);
                $result = self::delImportlogOutstorage($data);
                break;
        }

        return $result;
    }

    private static function delImportLogInStorage($data)
    {
        DB::beginTransaction();
        try {
            $inInfo = LogInStorageModel::query()
                ->where($data)->first();
            if (!empty($inInfo)) {
                $time = strtotime($inInfo['created_at']);
                LogInStorageModel::where('created_at', $time)
                    ->where(function ($query) use ($inInfo) {
                        if (!empty($inInfo['code_allocate_no'])) {
                            $query->where('code_allocate_no', $inInfo['code_allocate_no']);
                        }
                    })->update([
                        'delete_flag' => 1
                    ]);
                if (!empty($inInfo['code_allocate_no'])) {
                    LogOutStorageModel::query()
                        ->where('code_allocate_no', $inInfo['code_allocate_no'])
                        ->update([
                            'delete_flag' => 1
                        ]);;
                }
            }
            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        } catch (\Exception $e) {
            DB::rollBack();
            Log::debug('删除出入记录异常' . var_dump($e->getMessage(), true));
            return ['code' => 1, 'msg' => '删除失败', 'data' => ''];
        }

    }

    private static function delImportlogOutstorage($data)
    {
        DB::beginTransaction();
        try {
            $outInfo = LogOutStorageModel::query()
                ->where($data)->first();
            if (!empty($outInfo['code_allocate_no'])) {
                LogInStorageModel::query()
                    ->where('code_allocate_no', $outInfo['code_allocate_no'])
                    ->update([
                        'delete_flag' => 1
                    ]);;
            }
            LogOutStorageModel::query()
                ->where('created_at', strtotime($outInfo['created_at']))
                ->where(function ($query) use ($outInfo) {
                    if (!empty($outInfo['code_allocate_no'])) {
                        $query->where('code_allocate_no', $outInfo['code_allocate_no']);
                    }
                })->update([
                    'delete_flag' => 1
                ]);
            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        } catch (\Exception $e) {
            DB::rollBack();
            Log::debug('删除出入记录异常' . var_dump($e->getMessage(), true));
            return ['code' => 1, 'msg' => '删除失败', 'data' => ''];
        }

    }

    private static function logOutstorageDetail($data)
    {
        $basicInfo = LogOutStorageModel::query()->select(
            'log_outstorage.*',
            'a.label_name'
        )
            ->where('log_outstorage.id', $data['id'])
            ->leftJoin('custom_tag as a', 'a.id', '=', 'log_outstorage.label_id')
            ->first();

        $logInfo = LogOutstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name as next_storage_name',
            'f.storage_address as next_storage_address',
            'e.storage_name',
            'e.storage_address',
            'b.class_name as second_class_name',
            'b.class_no as second_class_no',
            'c.class_name as first_class_name',
            'c.class_no as first_class_no',
            'g.is_product_materiel',
            'g.id as type_id',
            'g.materiel_name',
            'g.type_name',
            'g.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.all_id_type',
            'a.all_id',
            'a.is_cancel',
            'a.label_name',
            'a.out_storage_time as operate_time',
//            'b.class_name as materiel_class_name',
            'a.last_upd_num',
            'd.username',
            'd.nickname',
            'g.is_use_serial',
            'a.serial_number',
            'i.batch_no',
            'a.sell_price',
//            'a.location_id as lo_id',
            'a.out_storage_time',
            'h.shelf_name',
            'location_name',
            'a.general_remarks',
            'a.upd_num',
            'g.materiel_unit',
            'a.batch_no as out_batch_no',
            'a.client_id',
            'product_type_id',
            'product_sell_price'
        )
            ->from('log_outstorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('storage as e', 'e.id', '=', 'a.storage_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.next_storage_id')
            ->leftJoin('materiel_type as g', 'g.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage_batch as i', 'i.id', '=', 'a.storage_batch_id')
            ->leftJoin('storage_manage as k', 'k.id', '=', 'a.curr_storage_manage_id')
            ->leftJoin('storage_shelf as h', 'h.id', '=', 'k.shelf_id')
            ->leftJoin('storage_shelf_location as j', 'j.id', '=', 'k.location_id')
            ->where([
                'a.created_at' => strtotime($basicInfo['created_at']),
                'a.type' => $basicInfo['type'],
                'a.user_id' => $basicInfo['user_id'],
            ])
            ->get()->toArray();
        $proofInfo = [];
        foreach ($logInfo as &$value) {
            if (empty($value['batch_no']) && !empty($value['out_batch_no'])) {
                $value['batch_no'] = explode(',', $value['out_batch_no']);
            }

            if ($value['all_id_type'] == 1) {
                $proofInfo = OverflowBreakageModel::select('proof_image')
                    ->where([
                        'id' => $value['all_id'],
                        'type' => 1,
                    ])->first();
            }
            if ($value['all_id_type'] == 2) {
                $proofInfo = SellModel::select('proof_image')
                    ->where([
                        'id' => $value['all_id'],
                    ])->first();
            }
            if (!empty($proofInfo['proof_image'])) {
                if (is_string($proofInfo['proof_image']) && strpos($proofInfo['proof_image'], ',') !== false) {
                    $value['proof_image'] = array_filter(explode(',', $proofInfo['proof_image']),
                        function ($v) {
                            return $v !== '';
                        });
                } else {
                    $value['proof_image'] = $proofInfo['proof_image'];
                }
            } else {
                $value['proof_image'] = [];
            }
            if (empty($value['next_storage_name'])) {
                $value['next_storage_name'] = '';
            }

            if (empty($value['next_storage_address'])) {
                $value['next_storage_address'] = '';
            }

            $value['shelf_name'] = empty($value['shelf_name']) ? '' : $value['shelf_name'];
            $value['location_name'] = empty($value['location_name']) ? '' : $value['location_name'];

            if (!empty($value['serial_number'])) {
                $value['serial_info'] = array_filter(explode(',', $value['serial_number']), function ($v) {
                    return $v !== '';
                });
                if ($value['is_product_materiel']) {
                    $productSerialInfo = SerialNumberModel::where([
                        'delete_flag' => 0,
                        'goods_id' => $value['type_id']
                    ])->whereIn('serial_no', $value['serial_info'])
                        ->get()->toArray();
                    //获取套餐序列号id
                    $parentId = [];

                    $goodsContentData = [];
                    foreach ($productSerialInfo as $parentValue) {
                        $parentId[] = $parentValue['id'];
                    }

                    //获取商品组件序列号信息
                    $nextSerialNumber = SerialNumberModel::select(
                        'serial_number.*',
                        'b.id as type_id',
                        'materiel_name',
                        'type_name'
                    )
                        ->whereIn('parent_id', $parentId)
                        ->where(['serial_number.delete_flag' => 0])
                        ->leftJoin('materiel_type as b', 'b.id', '=', 'serial_number.goods_id')
                        ->get()->toArray();

                    if (empty($nextSerialNumber)) {
                        $value['goods_serial_info'] = [];
                    } else {
                        foreach ($nextSerialNumber as $nextValue) {
                            if (!isset($goodsContentData[$nextValue['type_id']], $goodsContentData)) {
                                $goodsContentData[$nextValue['type_id']]['materiel_name'] = $nextValue['materiel_name'];
                                $goodsContentData[$nextValue['type_id']]['serial_content'][] = $nextValue['serial_no'];

                            } else {
                                $goodsContentData[$nextValue['type_id']]['serial_content'][] = $nextValue['serial_no'];
                            }
                        }

                        $value['goods_serial_info'] = array_values($goodsContentData);
                    }
                } else {
                    $value['goods_serial_info'] = [];
                }
            } else {
                $value['serial_info'] = [];
                $value['goods_serial_info'] = [];
            }

            $value['remark'] = empty($value['remark']) ? '' : $value['remark'];

            unset($value['serial_number']);
            $value['client_name'] = '';
            if (!empty($value['client_id'])) {
                $value['client_name'] = SupplierCustomerModel::query()
                    ->where(["id" => $value['client_id']])
                    ->value('name');
            }
            $updInLogList = UpdInOutLogModel::query()
                ->select(
                    "id",
                    "in_log_id",
                    "out_log_id",
                    "operate_num",
                    "last_num",
                    "diff_num",
                    "type"
                )->where([
                    'out_log_id' => $value['id']
                ])->get();
            if (!empty($updInLogList)) {
                foreach ($updInLogList as &$uVal) {
                    if (!empty($uVal['type'])) {
                        $uVal['diff_num'] = '-' . (float)$uVal['diff_num'];
                    } else {
                        $uVal['diff_num'] = '+' . (float)$uVal['diff_num'];
                    }
                }
            }
            $value['upd_log_list'] = $updInLogList ?? [];
            $value['product_name'] = MaterielTypeModel::query()
                ->where('id', $value['product_type_id'])->value('materiel_name');

        }

        if ($basicInfo['is_package']) {
            $packageName = PackageModel::where('id', $basicInfo['package_id'])->value('package_name');
        } else {
            $packageName = '';
        }
        switch ($basicInfo['all_id_type']) {
            case 1://报损
                $basicInfo['purchase_no'] = OverflowBreakageModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('overflow_breakage_no') ?? '';
                break;
            case 2://销售
                $basicInfo['purchase_no'] = SellModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('order_no') ?? '';
                break;
            case 6://换货出库
                $basicInfo['purchase_no'] = BarterModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('order_no') ?? '';
                break;
        }
        $result = [
            'id' => $basicInfo['id'],
            'type' => $basicInfo['type'],
            'all_id_type' => $basicInfo['all_id_type'],
            'label_name' => empty($basicInfo['label_name']) ? '' : $basicInfo['label_name'],
            'purchase_no' => empty($basicInfo['purchase_no']) ? '' : $basicInfo['purchase_no'],
            'package_name' => $packageName,
            'operate_time' => date('Y-m-d H:i:s', strtotime($basicInfo['out_storage_time'])),
            'general_remarks' => empty($logInfo[0]['general_remarks']) ? '' : $logInfo[0]['general_remarks'],
        ];

        $result['log_info'] = $logInfo;

        return $result;
    }

    //入库记录
    private static function logInStorageDetail($data)
    {
        $basicInfo = LogInStorageModel::select('log_instorage.*', 'a.label_name')
            ->where('log_instorage.id', $data['id'])
            ->leftJoin('custom_tag as a', 'a.id', '=', 'log_instorage.label_id')
            ->first();
        if (!empty($basicInfo)) $basicInfo = $basicInfo->toArray();
        $logInfo = LogInstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name as last_storage_name',
            'f.storage_address as last_storage_address',
            'e.storage_name',
            'e.storage_address',
            'b.class_name as second_class_name',
            'b.class_no as second_class_no',
            'c.class_name as first_class_name',
            'c.class_no as first_class_no',
            'g.is_product_materiel',
            'g.id as type_id',
            'g.materiel_name',
            'g.type_name',
            'g.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.all_id_type',
            'a.all_id',
            'a.remark',
            'a.is_cancel',
            'a.in_storage_time as operate_time',
            'a.purchase_no',
            'a.batch_no',
            'a.last_upd_num',
            'a.label_name',
            'd.username',
            'd.nickname',
            'g.is_use_serial',
            'g.is_product_materiel',
            'serial_number',
            'shelf_name',
            'location_name',
            'a.label_name',
            'a.general_remarks',
            'g.selling_price as sell_price',
            'a.upd_num',
            'g.materiel_unit',
            'i.upload_credentials_img as proof_image',
            'w.batch_no as batchNo',
            'a.supplier_id as client_id',
            'a.shelf_id',
            'a.location_id',
        )
            ->from('log_instorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('storage as e', 'e.id', '=', 'a.storage_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.last_storage_id')
            ->leftJoin('materiel_type as g', 'g.id', '=', 'materiel_type_id')
            ->leftJoin('storage_batch as i', 'i.batch_no', '=', 'a.batch_no')
            ->leftJoin('storage_batch as w', 'w.id', '=', 'a.batch_id')
            ->leftJoin('storage_manage as k', 'k.id', '=', 'a.curr_storage_manage_id')
            ->leftJoin('storage_shelf as h', 'h.id', '=', 'k.shelf_id')
            ->leftJoin('storage_shelf_location as j', 'j.id', '=', 'k.location_id')
            ->where([
                'a.created_at' => strtotime($basicInfo['created_at']),
                'a.type' => $basicInfo['type'],
                'a.user_id' => $basicInfo['user_id'],
            ])->get()->toArray();
        $proofInfo = [];

        foreach ($logInfo as &$value) {
            if (!empty($value['batch_no']) && !empty($value['batchNo'])) {
                $value['batch_no'] = $value['batch_no'] . ',' . $value['batchNo'];
            } elseif (empty($value['batch_no']) && !empty($value['batchNo'])) {
                $value['batch_no'] = $value['batchNo'];
            }
            if (!empty($value['batch_no'])) {
                $value['batch_no'] = array_filter(
                    explode(',', $value['batch_no']),
                    function ($v) {
                        return $v !== '';
                    });
            }
            if ($value['all_id_type'] == 1) {
                $proofInfo = OverflowBreakageModel::select('proof_image')
                    ->where([
                        'id' => $value['all_id'],
                        'type' => 0,
                    ])->first();
            }
            if ($value['all_id_type'] == 2) {
                $proofInfo = SalesReturnModel::select('proof_image')
                    ->where([
                        'id' => $value['all_id'],
                    ])->first();
            }
            if ($value['all_id_type'] == 3) {
                $proofInfo = MaterielModel::query()
                    ->where([
                        'id' => $value['all_id'],
                    ])->first();
                $value['client_id'] = $proofInfo['id'];
            }

            if (!empty($value['proof_image'])) {
                if (is_string($value['proof_image']) && strpos($value['proof_image'], ',') !== false) {
                    $value['proof_image'] = array_filter(explode(',', $value['proof_image']),
                        function ($v) {
                            return $v !== '';
                        });
                } else {
                    $value['proof_image'] = array($value['proof_image']);
                }
            } else {
                $value['proof_image'] = [];
            }

            if (!empty($proofInfo['proof_image'])) {
                if (is_string($proofInfo['proof_image']) && strpos($proofInfo['proof_image'], ',') !== false) {
                    $value['proof_image'] = array_filter(explode(',', $proofInfo['proof_image']),
                        function ($v) {
                            return $v !== '';
                        });
                } else {
                    $value['proof_image'] = array($proofInfo['proof_image']);
                }
            }

            if (empty($value['last_storage_name'])) {
                $value['last_storage_name'] = '';
            }

            if (empty($value['last_storage_address'])) {
                $value['last_storage_address'] = '';
            }

            $value['shelf_name'] = empty($value['shelf_name']) ? '' : $value['shelf_name'];
            $value['location_name'] = empty($value['location_name']) ? '' : $value['location_name'];

            if (!empty($value['serial_number'])) {
                $value['serial_info'] = array_values(array_filter(explode(',', $value['serial_number']), function ($v) {
                    return $v !== '';
                }));
                if ($value['is_product_materiel']) {
                    $productSerialInfo = SerialNumberModel::where([
                        'goods_id' => $value['type_id'],
                        'delete_flag' => 0
                    ])->whereIn('serial_no', $value['serial_info'])
                        ->get()->toArray();
                    //获取套餐序列号id
                    $parentId = [];
                    $goodsContentData = [];
                    foreach ($productSerialInfo as $parentValue) {
                        $parentId[] = $parentValue['id'];
                    }

                    //获取商品组件序列号信息
                    $nextSerialNumber = SerialNumberModel::select(
                        'serial_number.*',
                        'b.id as type_id',
                        'materiel_name',
                        'type_name'
                    )->whereIn('parent_id', $parentId)
                        ->where(['serial_number.delete_flag' => 0])
                        ->leftJoin('materiel_type as b', 'b.id', '=', 'serial_number.goods_id')
                        ->get()->toArray();

                    if (empty($nextSerialNumber)) {
                        $value['goods_serial_info'] = [];
                    } else {
                        foreach ($nextSerialNumber as $nextValue) {
                            if (!isset($goodsContentData[$nextValue['type_id']], $goodsContentData)) {
                                $goodsContentData[$nextValue['type_id']]['materiel_name'] = $nextValue['materiel_name'];
                                $goodsContentData[$nextValue['type_id']]['type_name'] = $nextValue['type_name'];
                                $goodsContentData[$nextValue['type_id']]['serial_content'][] = $nextValue['serial_no'];

                            } else {
                                $goodsContentData[$nextValue['type_id']]['serial_content'][] = $nextValue['serial_no'];
                            }
                        }

                        $value['goods_serial_info'] = array_values($goodsContentData);
                    }
                } else {
                    $value['goods_serial_info'] = [];
                }
            } else {
                $value['serial_info'] = [];
                $value['goods_serial_info'] = [];
            }

            unset($value['serial_number']);

            $value['remark'] = empty($value['remark']) ? '' : $value['remark'];
            $value['client_name'] = '';
            if (!empty($value['client_id'])) {
                $value['client_name'] = SupplierCustomerModel::query()
                    ->where('id', $value['client_id'])->value('name');
            }

            $updInLogList = UpdInOutLogModel::query()
                ->select(
                    "id",
                    "in_log_id",
                    "out_log_id",
                    "operate_num",
                    "last_num",
                    "diff_num",
                    "type"
                )->where([
                    'in_log_id' => $value['id']
                ])->get();
            if (!empty($updInLogList)) {
                foreach ($updInLogList as &$uVal) {
                    if (!empty($uVal['type'])) {
                        $uVal['diff_num'] = '-' . (float)$uVal['diff_num'];
                    } else {
                        $uVal['diff_num'] = '+' . (float)$uVal['diff_num'];
                    }
                }
            }
            $value['upd_log_list'] = $updInLogList ?? [];
        }
        if ($basicInfo['all_id_type'] == 3) {
            $basicInfo['in_storage_time'] = $basicInfo['created_at'];

        } else {
            $basicInfo['in_storage_time'] = date('Y-m-d H:i:s', strtotime($basicInfo['in_storage_time']));
        }

        switch ($basicInfo['all_id_type']) {
            case 1://报溢
                $basicInfo['purchase_no'] = OverflowBreakageModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('overflow_breakage_no') ?? '';
                break;
            case 2://退货
            case 9://退换货入库
                $basicInfo['purchase_no'] = SalesReturnModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('order_no') ?? '';
                break;
            case 3://采购
                $basicInfo['purchase_no'] = MaterielModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('purchase_no') ?? '';
                break;
            case 4://生产订单
                $basicInfo['purchase_no'] = ProductOrderModel::query()
                    ->where('id', $basicInfo['all_id'])
                    ->value('product_no') ?? '';
                break;
        }
        $result = [
            'id' => $basicInfo['id'],
            'type' => $basicInfo['type'],
            'all_id_type' => $basicInfo['all_id_type'],
            'purchase_no' => $basicInfo['purchase_no'],
            'label_name' => empty($basicInfo['label_name']) ? '' : $basicInfo['label_name'],
            'general_remarks' => empty($logInfo[0]['general_remarks']) ? '' : $logInfo[0]['general_remarks'],
            'operate_time' => $basicInfo['in_storage_time'],
        ];
        $result['log_info'] = $logInfo;
        $result['upd_log_list'] = $updInLogList ?? [];
        return $result;
    }

    //v3.2.6开始废弃
    public static function cancelStorageLog(array $data)
    {
        DB::beginTransaction();

        try {
            switch ($data['type']) {
                case 0:
                    $result = self::cancelDirectInstorage($data);
                    break;
                default:
                    $result = self::cancelDirectOutstorage($data);
            }

            CommonService::setAlertFlag($data['main_id']);
            CommonService::cancelAlertFlag($data['main_id']);

            DB::commit();
            return $result;
        } catch (Exception $e) {
            DB::rollBack();
            Log::debug('出入库记录撤销异常:' . var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    public static function logShelfInfo(array $data)
    {
        $inLog = LogInStorageModel::query()->select(
            'a.shelf_id',
            'shelf_name',
            'a.location_id',
            'location_name',
            'd.materiel_name',
            'd.type_name',
            'd.materiel_unit',
            DB::raw('SUM(operate_num) as operate_num')
        )
            ->from('log_instorage as a')
            ->leftJoin('storage_shelf as b', 'a.shelf_id', '=', 'b.id')
            ->leftJoin('storage_shelf_location as c', 'a.location_id', '=', 'c.id')
            ->leftJoin('materiel_type as d', 'd.id', '=', 'a.materiel_type_id')
            ->where([
                'a.main_id' => $data['main_id'],
                'materiel_type_id' => $data['type_id'],
                'a.storage_id' => $data['storage_id'],
            ])
            ->where('a.is_cancel', 0)
            ->groupBy('location_id')
            ->get()->toArray();

        $outLog = LogOutStorageModel::query()->select(
            'a.shelf_id',
            'shelf_name',
            'a.location_id',
            'location_name',
            'd.materiel_name',
            'd.type_name',
            DB::raw('SUM(operate_num) as operate_num')
        )
            ->from('log_outstorage as a')
            ->leftJoin('storage_shelf as b', 'a.shelf_id', '=', 'b.id')
            ->leftJoin('storage_shelf_location as c', 'a.location_id', '=', 'c.id')
            ->leftJoin('materiel_type as d', 'd.id', '=', 'a.materiel_type_id')
            ->where([
                'a.main_id' => $data['main_id'],
                'materiel_type_id' => $data['type_id'],
                'a.storage_id' => $data['storage_id'],
            ])
            ->where('a.is_cancel', 0)
            ->groupBy('location_id')
            ->get()->toArray();

        $result = [];
        if (!empty($inLog)) {
            foreach ($inLog as $value) {
                $newVal = $value;
                if (!empty($outLog)) {
                    foreach ($outLog as $val) {
                        if ($val['location_id'] == $value['location_id']) {
                            $newVal = [
                                'shelf_id' => $value['shelf_id'],
                                'shelf_name' => empty($value['shelf_name']) ? '' : $value['shelf_name'],
                                'operate_num' => $value['operate_num'] - $val['operate_num'],
                                'location_id' => $value['location_id'],
                                'location_name' => empty($value['location_name']) ? '' : $value['location_name'],
                                'materiel_name' => $value['materiel_name'],
                                'type_name' => empty($value['type_name']) ? '' : $value['type_name'],
                                'materiel_unit' => empty($value['materiel_unit']) ? '' : $value['materiel_unit'],
                            ];
                        }
                    }
                }
                $result[] = $newVal;
            }
        }

        return $result;
    }

    static private function logInstorageDetailOld($data)
    {
        $info = LogInstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name as last_storage_name',
            'f.storage_address as last_storage_address',
            'e.storage_name',
            'e.storage_address',
//            'a.materiel_class_name',
//            'a.materiel_class_no',
            'g.materiel_name',
            'g.type_name',
            'g.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.all_id_type',
            'a.all_id',
            'a.remark',
            'a.is_cancel',
            'a.in_storage_time',
            'a.purchase_no',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',
            'c.class_name',
            'c.class_no',
            'd.username',
            'd.nickname',
            'g.is_use_serial',
            'serial_number',
            'i.batch_no'
        )
            ->from('log_instorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('storage as e', 'e.id', '=', 'a.storage_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.last_storage_id')
            ->leftJoin('materiel_type as g', 'g.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage_batch as i', 'i.id', '=', 'a.batch_id')
            ->where([
                'a.id' => $data['id'],
            ])
            ->first();

        if (!empty($info['serial_number'])) {
            $info['serial_number'] = array_filter(explode(',', $info['serial_number']), function ($v) {
                return $v !== '';
            });

        } else {
            $info['serial_number'] = [];
        }

        switch ($info['all_id_type']) {
            case 0://无
            case 1://报溢
            case 6://组件返仓
                $info['order_no'] = '';
                break;
            case 2://退货
                $salesReturnInfo = SalesReturnModel::where('id', $info['all_id'])->first();
                $info['order_no'] = $salesReturnInfo['order_no'];
                break;
            case 3://采购
                $materielInfo = MaterielModel::where('id', $info['all_id'])->first();
                $info['order_no'] = $materielInfo['order_no'];
                break;
            case 4://生产订单
                $productOrderInfo = ProductOrderModel::where('id', $info['all_id'])->first();
                $info['order_no'] = $productOrderInfo['product_no'];
                break;
        }

        return $info;
    }

    //出库操作记录详细-v3.2.6废弃
    static private function logOutstorageDetailOld($data)
    {
        $info = LogOutstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name as next_storage_name',
            'f.storage_address as next_storage_address',
            'e.storage_name',
            'e.storage_address',
            'a.materiel_type_id as goods_id',
//                'a.materiel_class_no',
            'g.materiel_name',
            'g.type_name',
            'g.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.all_id_type',
            'a.all_id',
            'a.is_cancel',
            'a.out_storage_time',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',
            'c.class_name',
            'c.class_no',
            'd.username',
            'd.nickname',
            'g.is_use_serial',
            'a.serial_number',
            'i.batch_no',
            'a.shelf_id as sh_id',
            'a.location_id as lo_id',
            'a.out_storage_time'
        )
            ->from('log_outstorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('storage as e', 'e.id', '=', 'a.storage_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.next_storage_id')
            ->leftJoin('materiel_type as g', 'g.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage_batch as i', 'i.id', '=', 'a.storage_batch_id')
            ->where([
                'a.id' => $data['id']
            ])
            ->first();

        if (!empty($info['serial_number'])) {
            $loCondition = [];
            $serialArr = [];
            $loCondition['shelf_id'] = $info['sh_id'];
            $loCondition['location_id'] = $info['lo_id'];
            $loCondition['out_storage_time'] = strtotime($info['out_storage_time']);
            $loCondition['materiel_type_id'] = $info['goods_id'];
            $loList = LogOutstorageModel::select('serial_number')->where($loCondition)->get()->toArray();

            if (!empty($loList)) {
                foreach ($loList as $key => $val) {
                    if (!empty($val['serial_number'])) {
                        $serialData = explode(',', $val['serial_number']);
                        if (is_array($serialData)) {
                            foreach ($serialData as $sKey => $sVal) {
                                if (!empty($sVal)) {
                                    $serialArr[] = $sVal;
                                }
                            }
                        } else {
                            $serialArr[] = $val['serial_number'];
                        }
                    }
                }
            }
            $info['serial_number'] = $serialArr;
        } else {
            $info['serial_number'] = [];
        }

        switch ($info['all_id_type']) {
            case 0://无
            case 1://报损
                $info['order_no'] = '';
                break;
            case 2://销售
                $sellInfo = SellModel::where('id', $info['all_id'])->first();
                $info['order_no'] = $sellInfo['order_no'];
                break;
            case 3://生产订单
                $productOrderInfo = ProductOrderModel::where('id', $info['all_id'])->first();
                $info['order_no'] = $productOrderInfo['product_no'];
                break;
        }

        return $info;
    }

    //套餐出库记录详细
    static public function logPackageContentDetail($data)
    {
        $datas = LogPackageModel::select(
            'a.id',
            'c.package_name',
            'num',
            'remark',
            'a.all_id_type',
            'a.all_id',
            'a.created_at',
            'username',
            'nickname',
            'is_cancel',
            'a.remark'
        )
            ->from('log_package as a')
            ->leftJoin('admin as b', 'b.id', '=', 'a.user_id')
            ->with('hasManyContent', function ($query) {
                $query->select(
                    'log_package_content.id',
                    'log_package_id',
                    'a.storage_name',
                    'a.storage_address',
                    'b.class_name as second_class_name',
                    'c.class_name as first_class_name',
                    'd.materiel_name',
                    'd.type_name',
                    'operate_num',
                    'e.in_storage_num',
                    'd.is_use_serial',
                    'log_package_content.serial_number',
                    'i.batch_no'
                )
                    ->leftJoin('storage as a', 'a.id', '=', 'log_package_content.storage_id')
                    ->leftJoin('materiel_class as b', 'b.id', '=', 'log_package_content.materiel_class_id')
                    ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
                    ->leftJoin('materiel_type as d', 'd.id', '=', 'log_package_content.materiel_type_id')
                    ->leftJoin('storage_manage as e', 'e.id', '=', 'log_package_content.out_storage_manage_id')
                    ->leftJoin('storage_batch as i', 'i.id', '=', 'log_package_content.storage_batch_id');
            })
            ->leftJoin('package as c', 'c.id', '=', 'a.package_id')
            ->where('a.id', $data['id'])
            ->get()->toArray();
        if (!empty($datas[0]['has_many_content'])) {
            foreach ($datas[0]['has_many_content'] as &$v) {
                if (!empty($v['serial_number'])) {
                    $v['serial_number'] = explode(',', $v['serial_number']);
                } else {
                    $v['serial_number'] = [];
                }
            }
        }
        $arr['id'] = $datas[0]['id'];
        $arr['package_name'] = $datas[0]['package_name'];
        $arr['num'] = $datas[0]['num'];
        $arr['remark'] = $datas[0]['remark'];
        $arr['created_at'] = $datas[0]['created_at'];
        $arr['username'] = $datas[0]['username'];
        $arr['nickname'] = $datas[0]['nickname'];
        $arr['is_cancel'] = $datas[0]['is_cancel'];
        $arr['content'] = $datas[0]['has_many_content'];

        switch ($arr['all_id_type']) {
            case 0://无
            case 1://报损
                $info['order_no'] = '';
                break;
            case 2://销售
                $sellInfo = SellModel::where('id', $arr['all_id'])->first();
                $info['order_no'] = $sellInfo['order_no'];
                break;
            case 3://退货
                $salesReturnInfo = SalesReturnModel::where('id', $arr['all_id'])->first();
                $info['order_no'] = $salesReturnInfo['order_no'];
                break;
        }

        return $arr;
    }


    static public function logDel($data, $logIdArr, $condition)
    {
        switch ($data['type']) {
            //入库
            case 0:
                $result = self::instorageDel($logIdArr, $condition);
                break;
            //出库
            case 1:
                $result = self::outstorageDel($logIdArr, $condition);
                break;
            //套餐出库
            case 2:
                $result = self::packageOutstorageDel($logIdArr, $condition);
                break;
        }

        return $result;
    }

    static private function instorageDel($logIdArr, $condition)
    {
        $basicInfo = LogInStorageModel::query()->whereIn('id', $logIdArr)
            ->get()->toArray();

        $data = [];
        foreach ($basicInfo as $value) {
            $logInfo = LogInStorageModel::query()->where([
                'type' => $value['type'],
                'created_at' => strtotime($value['created_at']),
            ])
                ->get()->toArray();

            foreach ($logInfo as $val) {
                $data[] = $val['id'];
            }
        }

        LogInStorageModel::whereIn('id', $data)->update(['delete_flag' => 1]);

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    static private function outstorageDel($logIdArr, $condition)
    {
        $basicInfo = LogOutStorageModel::query()->whereIn('id', $logIdArr)
            ->get()->toArray();

        $data = [];
        foreach ($basicInfo as $value) {
            $logInfo = LogOutStorageModel::query()->where([
                'type' => $value['type'],
                'created_at' => strtotime($value['created_at']),
            ])
                ->get()->toArray();

            foreach ($logInfo as $val) {
                $data[] = $val['id'];
            }
        }

        LogOutStorageModel::whereIn('id', $data)->update(['delete_flag' => 1]);

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    static private function packageOutstorageDel($logIdArr, $condition)
    {
        foreach ($logIdArr as $value) {
            $logInfo = LogPackageModel::where([
                'id' => $value,
                'delete_flag' => 0
            ])
                ->where($condition)
                ->first();

            if (empty($logInfo)) {
                return ['code' => 1, 'msg' => '目标日志不存在,请重试', 'data' => ''];
            }

            if (!$logInfo['is_cancel']) {
                return ['code' => 1, 'msg' => '目标日志未撤销，不可删除', 'data' => ''];
            }
        }

        LogPackageModel::whereIn('id', $logIdArr)->update(['delete_flag' => 1]);

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }


    //操作记录列表
    static public function list($data)
    {
        $keywordCondition = [];
        if (!empty($data['keyword'])) {
            switch ($data['keyword_type']) {
                case 0://商品名
                    $keywordCondition[] = ['e.materiel_name', 'like', '%' . $data['keyword'] . '%'];
                    break;
                case 1://型号名
                    $keywordCondition[] = ['e.type_name', 'like', '%' . $data['keyword'] . '%'];
                    break;
                case 2://商品编号
                    $keywordCondition[] = ['e.materiel_no', 'like', '%' . $data['keyword'] . '%'];
                    break;
                case 3://仓库名
                    $keywordCondition[] = ['f.storage_name', 'like', '%' . $data['keyword'] . '%'];
                    break;
                case 4://序列号
                    $keywordCondition[] = ['a.serial_number', 'like', '%' . $data['keyword'] . '%'];
                    break;
                case 5://操作人名称
                    $keywordCondition[] = ['d.nickname', 'like', '%' . $data['keyword'] . '%'];
                    break;
            }
        }

        //DB::enableQueryLog();
        switch ($data['type']) {
            //入库
            case 0:
                $result = self::instorageList($data, $keywordCondition);
                break;
            //出库
            case 1:
                $result = self::outstorageList($data, $keywordCondition);
                break;

        }
        $result['field_list'] = [];
        if ($data['user_id'] !== $data['main_id']) {
            $result['field_list'] = DataFieldPowerAdminModel::query()
                ->leftJoin('data_field_power_list as b',
                    'b.id', '=', 'data_field_power_admin.field_id'
                )->where([
                    'b.status' => 1,
                    'data_field_power_admin.status' => 1,
                    'admin_id' => $data['user_id'],
                ])->pluck('mark');
        }
        return $result;
    }

    /**
     * 对操作记录进行分组
     * Author: Sw
     * Created at 2023/3/10 16:21
     * @param $arr
     * @param $fields
     * @return array|mixed
     */
    private static function groupArray($arr, $fields)
    {

        if (empty($fields) || !is_array($fields)) {
            return $arr;
        }

        $newArr = array(); // so that we always return an array
        $field = array_shift($fields);

        foreach ($arr as $val) {
            $newArr[$val[$field]][] = $val;
        }

        foreach (array_keys($newArr) as $key) {
            // Since we shifted one field off before, this groups by the remaining
            $newArr[$key] = self::groupArray($newArr[$key], $fields);
        }

        return $newArr;
    }

    private static function assignList($data, $query)
    {
        $groups = array('created_at', 'main_id', 'user_id');
        $assignData = self::groupArray($query, $groups);

        $arr = [];
        foreach ($assignData as $value) {
            foreach ($value as $val) {
                foreach ($val as $v) {
                    $arr[] = $v;
                }
            }
        }
        $arr1 = [];
        foreach ($arr as $key => $v1) {

            if ($v1[0]['all_id_type'] == 3) {

                $v1[0]['operate_time'] = $v1[0]['created_at'];
            } else {
                $v1[0]['operate_time'] = date('Y-m-d H:i:s', $v1[0]['operate_time']);
            }

            $arr1[$key]['type'] = $v1[0]['type'];
            $arr1[$key]['operate_time'] = $v1[0]['operate_time'];
            $arr1[$key]['nickname'] = $v1[0]['nickname'];
            $arr1[$key]['type'] = $v1[0]['type'];
            $arr1[$key]['all_id_type'] = $v1[0]['all_id_type'];
            $arr1[$key]['id'] = $v1[0]['id'];
            $arr1[$key]['upd_num'] = $v1[0]['upd_num'];
            $arr1[$key]['label_name'] = $v1[0]['label_name'];
            $arr1[$key]['general_remarks'] = $v1[0]['general_remarks'];
            $arr1[$key]['batch_id'] = !empty($v1[0]['batch_id']) ? $v1[0]['batch_id'] : 0;
            $arr1[$key]['serial_number'] = !empty($v1[0]['serial_number']) ? explode(',', $v1[0]['serial_number']) : [];
            $arr1[$key]['is_use_serial'] = $v1[0]['is_use_serial'];
            $arr1[$key]['batch_no'] = !empty($v1[0]['batch_no']) ? $v1[0]['batch_no'] : '';
            $arr1[$key]['last_upd_num'] = $v1[0]['last_upd_num'];
            $v1[0]['is_package'] = !empty($v1[0]['is_package']) ? 1 : 0;

            if ($v1[0]['is_package']) {
                $packageInfo = PackageModel::where('id', $v1[0]['package_id'])->first();
                $arr1[$key]['package_name'] = $packageInfo['package_name'];
            } else {
                $arr1[$key]['package_name'] = '';
            }

            $cancelSign = 1;
            foreach ($v1 as $v2) {
                $info = [];
                if (!empty($v2['is_use_packages_module']) && !empty($v2['product_type_id'])) {
                    $info = MaterielTypeModel::query()
                        ->where('id', $v2['product_type_id'])->first();
                }
                $arr1[$key]['content'][] = [
                    'first_class_name' => !empty($v2['first_class_name']) ? $v2['first_class_name'] : '',
                    'first_class_no' => !empty($v2['first_class_no']) ? $v2['first_class_no'] : '',
                    'second_class_name' => !empty($v2['second_class_name']) ? $v2['second_class_name'] : '',
                    'second_class_no' => !empty($v2['second_class_no']) ? $v2['second_class_no'] : '',
                    'materiel_name' => $v2['all_id_type'] == 7 ? $v2['goods_name'] : $v2['materiel_name'],
                    'type_name' => $v2['type_name'],
                    'operate_num' => $v2['operate_num'],
                    'materiel_no' => $v2['materiel_no'],
                    'materiel_unit' => $v2['materiel_unit'],
                    'is_product_materiel' => $v2['is_product_materiel'],
                    'label_name' => $v2['label_name'],
                    'general_remarks' => $v2['general_remarks'],
                    'batch_id' => $v2['batch_id'],
                    'serial_number' => !empty($v2['serial_number']) ? explode(',', $v2['serial_number']) : [],
                    'is_use_serial' => $v2['is_use_serial'],
                    'batch_no' => !empty($v2['batch_no']) ? $v2['batch_no'] : '',
                    'last_upd_num' => $v2['last_upd_num'],
                    'product_type_id' => !empty($info['id']) ? $info['id'] : '',
                    'product_name' => !empty($info['materiel_name']) ? $info['materiel_name'] : '',
                    'product_sell_price' => !empty($v2['product_sell_price']) ? $v2['product_sell_price'] : '',
                ];

                if (!$v2['is_cancel']) {
                    $cancelSign = 0;
                }
            }
            $arr1[$key]['is_cancel'] = $cancelSign;
        }

        //撤销状态;0:未撤销;1:已撤销;
        if ($data['status']) {
            foreach ($arr1 as $k3 => $v3) {
                if (!$v3['is_cancel']) {
                    unset($arr1[$k3]);
                }
            }
        } else {
            foreach ($arr1 as $k3 => $v3) {
                if ($v3['is_cancel']) {
                    unset($arr1[$k3]);
                }
            }
        }

        $currentPage = $data['currentPage'];
        $result = array_slice($arr1, --$data['currentPage'] * $data['pageSize'], $data['pageSize']);
        return [
            'total' => count($arr1),
            'current_page' => $currentPage,
            'next_page_url' => count($result) < $data['pageSize'] ? null : config('app.v3_2_6_url') . "storage_manage_list?=" . ($data['currentPage'] + 1),
            'prev_page_url' => $currentPage == 1 ? null : config('app.url') . "storage_manage_list?=" . ($currentPage - 1),
            "path" => config('app.v3_2_6_url') . "storage_manage_list",
            "to" => $currentPage * $data['pageSize'],
            'data' => $result,
            "per_page" => $data['pageSize']
        ];
    }

    //入库操作记录
    static private function instorageList($data, $keywordCondition)
    {
        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['a.user_id'] = ['EQ' => $data['user_id']];
            }
        }

        $condition = [];
        switch ($data['log_type']) {
            case 0://全部不包括撤销
                if ($data['status'] == 0) {
                    $condition[] = ['type', '!=', 7];
                    $condition[] = ['all_id_type', '!=', 8];
                }
                break;
            case 1://报溢入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 1];
                break;
            case 2://退货入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 2];
                break;
            case 3://采购入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 4://生产订单入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 5://调拨入库
                $condition['type'] = ['EQ' => 1];
                break;
            case 6://直接入库
                $condition['type'] = ['EQ' => 2];
                break;
            case 7://生产订单还库
                $condition['type'] = ['EQ' => 3];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 8://扫码入库
                $condition['type'] = ['EQ' => 4];
                break;
            case 9://套件返仓
                $condition['type'] = ['EQ' => 5];
                break;
            case 10://导入入库
                $condition['type'] = ['EQ' => 6];
                $condition['all_id_type'] = ['EQ' => 7];
                break;
            case 11://导入入库
                $condition['type'] = ['EQ' => 7];
                $condition['all_id_type'] = ['EQ' => 8];
                break;
            case 12://退换货入库
                $condition['type'] = ['EQ' => 8];
                $condition['all_id_type'] = ['EQ' => 9];
                break;
            case 13://扫码调拨入库
                $condition['type'] = ['EQ' => 9];
                $condition['all_id_type'] = ['EQ' => 10];
                break;
        }

        /*$query = Cache::remember($data['domain'].'_in_list_userId_'.$data['user_id'], 30, function()
        use($condition,$operateCondition,$keywordCondition,$data) {*/
        $query = LogInstorageModel::select(
            'a.id',
            'a.type',
            'b.class_name as second_class_name',
            'b.class_no as second_class_no',
            'c.class_name as first_class_name',
            'c.class_no as first_class_no',
            'e.materiel_name',
            'e.type_name',
            'e.materiel_unit',
            'e.is_product_materiel',
            'a.operate_num',
            'a.in_storage_time as operate_time',
            'd.nickname',
            'a.created_at',
            'a.user_id',
            'a.main_id',
            'a.is_cancel',
            'a.all_id_type',
            'a.materiel_no',
            'a.upd_num',
            'a.batch_id',
            'a.serial_number',
            'e.is_use_serial',
            'a.label_name',
            'a.general_remarks',
            //'j.batch_no',
            'a.last_upd_num',
            'a.materiel_name as goods_name'
        )
            ->from('log_instorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.materiel_type_id')
            /* ->leftJoin('storage as f', 'f.id', '=', 'a.storage_id')
             ->leftJoin('storage as g', 'g.id', '=', 'a.last_storage_id')
             ->leftJoin('storage_shelf_location as h','h.id','=','a.location_id')
             ->leftJoin('storage_shelf as i','i.id','=','a.shelf_id')
             ->leftJoin('storage_batch as j','j.id','=','a.batch_id')*/
            ->where($condition)
            ->where($operateCondition)
            ->where('a.delete_flag', 0)
            ->where('a.is_cancel', $data['status']);
        if (!empty($data['f_class_id'])) {
            $secClassId = MaterielClassModel::query()
                ->where([
                    'delete_flag' => 0,
                    'main_id' => $data['main_id'],
                    'parent_id' => $data['f_class_id']
                ])->pluck('id');
            if (!empty($secClassId)) {
                $query->whereIn('e.materiel_class_id', $secClassId->toArray());
            }
        }
        if ($data['materiel_class_id'] != 0) {
            $query->where('a.materiel_class_id', $data['materiel_class_id']);
        }

        if (!empty($data['label_id'])) {
            $query->where('a.label_id', $data['label_id']);
        }

        $keyword = empty($data['keyword']) ? '' : $data['keyword'];

        if (!empty($data['start_time'])) {
            $startTimeArr = explode(' ', $data['start_time']);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($data['end_time'])) {
            $endTimeArr = explode(' ', $data['end_time']);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query->whereBetween('in_storage_time', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query->where('in_storage_time', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query->where('in_storage_time', '<=', $endTime);
        }

        $query = $query->where(function ($query) use ($keywordCondition, $data) {
            if (!empty($keywordCondition) || !empty($data['keyword'])) {
                $query->orWhere($keywordCondition);
                if ($data['type'] == 0) {
                    $query->orWhere('purchase_no', 'like', '%' . $data['keyword'] . '%');
                }
            }
        })
            ->orderBy('a.id', 'desc')
            ->limit(10000)
            ->get();
        /*return*/
        $query = !empty($query) ? $query->toArray() : [];
        /* });*/

        return self::assignList($data, $query);
    }

    //出库操作记录
    static private function outstorageList($data, $keywordCondition)
    {

        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['a.user_id'] = ['EQ' => $data['user_id']];
            }
        }

        $condition = [];

        switch ($data['log_type']) {
            case 0://全部不包括撤销
                if ($data['status'] == 0) {
                    $condition[] = ['type', '!=', 8];
                    $condition[] = ['all_id_type', '!=', 5];
                }
                break;
            case 1://报损出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 1];
                break;
            case 2://销售出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 2];
                break;
            case 3://生产订单出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 4://调拨出库
                $condition['type'] = ['EQ' => 1];
                break;
            case 5://直接出库
                $condition['type'] = ['EQ' => 2];
                break;
            case 6://生产订单补足
                $condition['type'] = ['EQ' => 3];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 7://扫码出库
                $condition['type'] = ['EQ' => 4];
                break;
            case 8://套餐拆解
                $condition['type'] = ['EQ' => 5];
                break;
            case 9://老版本套餐
                $condition['type'] = ['EQ' => 6];
                break;
            case 10://导入出库
                $condition['type'] = ['EQ' => 7];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 11://导入出库
                $condition['type'] = ['EQ' => 8];
                $condition['all_id_type'] = ['EQ' => 5];
                break;
            case 12://换货出库
                $condition['type'] = ['EQ' => 9];
                $condition['all_id_type'] = ['EQ' => 6];
                break;
            case 13://生产损耗出库
                $condition['type'] = ['EQ' => 10];
                $condition['all_id_type'] = ['EQ' => 7];
                break;
            case 14://扫码调拨入库
                $condition['type'] = ['EQ' => 11];
                $condition['all_id_type'] = ['EQ' => 8];
                break;

        }
        /* $query = Cache::remember($data['domain'].'out_list_userId_'.$data['user_id'], 30, function()
         use($condition,$operateCondition,$keywordCondition,$data) {*/
        $query = LogOutstorageModel::query()->select(
            'a.id',
            'a.type',
            /*'b.class_name as second_class_name',
            'b.class_no as second_class_no',
            'c.class_name as first_class_name',
            'c.class_no as first_class_no',*/
            'e.materiel_name',
            'e.type_name',
            'e.materiel_no',
            'a.is_package',
            'a.package_id',
            'e.materiel_unit',
            'e.is_product_materiel',
            'a.operate_num',
            'a.is_cancel',
            'a.out_storage_time as operate_time',
            'a.main_id',
            'a.created_at',
            'd.nickname',
            'a.all_id_type',
            'a.user_id',
            'a.upd_num',
            'a.storage_batch_id as batch_id',
            'a.serial_number',
            'e.is_use_serial',
            'a.label_name',
            'a.general_remarks',
            /*'j.batch_no',*/
            'a.last_upd_num',
            'is_use_packages_module',
            'product_type_id',
            'product_sell_price'
        )
            ->from('log_outstorage as a')
            /* ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
             ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')*/
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.materiel_type_id')
            /*->leftJoin('storage as f', 'f.id', '=', 'a.storage_id')
            ->leftJoin('storage as g', 'g.id', '=', 'a.next_storage_id')
            ->leftJoin('storage_shelf_location as h','h.id','=','a.location_id')
            ->leftJoin('storage_shelf as i','i.id','=','a.shelf_id')
            ->leftJoin('storage_batch as j','j.id','=','a.storage_batch_id')*/
            ->where('a.delete_flag', 0)
            ->where($condition)
            ->where($operateCondition)
            ->where('a.is_cancel', $data['status']);
        if (!empty($data['f_class_id'])) {
            $secClassId = MaterielClassModel::query()
                ->where([
                    'delete_flag' => 0,
                    'main_id' => $data['main_id'],
                    'parent_id' => $data['f_class_id']
                ])->pluck('id');
            if (!empty($secClassId)) {
                $query->whereIn('e.materiel_class_id', $secClassId);
            }
        }
        if ($data['materiel_class_id'] != 0) {
            $query->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
                ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id');
            $query->where('a.materiel_class_id', $data['materiel_class_id']);
        }

        if (!empty($data['label_id'])) {
            $query->where('a.label_id', $data['label_id']);
        }

        $keyword = empty($data['keyword']) ? '' : $data['keyword'];

        if (!empty($data['start_time'])) {
            $startTimeArr = explode(' ', $data['start_time']);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($data['end_time'])) {
            $endTimeArr = explode(' ', $data['end_time']);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query->whereBetween('out_storage_time', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query->where('out_storage_time', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query->where('out_storage_time', '<=', $endTime);
        }
        $query = $query->where(function ($query) use ($keywordCondition, $data) {
            if (!empty($keywordCondition) || !empty($data['keyword'])) {
                $query->orWhere($keywordCondition);
                if ($data['type'] == 0) {
                    $query->orWhere('purchase_no', 'like', '%' . $data['keyword'] . '%');
                }
            }
        })->orderBy('a.id', 'desc')->limit(10000)->get();
        /*return*/
        $query = !empty($query) ? $query->toArray() : [];
        /*});*/
        return self::assignList($data, $query);
    }

    private static function exportDataAssignList($data, $query): array
    {
        $groups = array('created_at', 'main_id');
        $assignData = self::groupArray($query, $groups);

        $arr = [];
        foreach ($assignData as $value) {
            foreach ($value as $val) {
                $arr[] = $val;
            }
        }

        $arr1 = [];
        foreach ($arr as $key => $v1) {
            $arr1[$key]['type'] = $v1[0]['type'];
            $arr1[$key]['operate_time'] = date('Y-m-d H:i:s', $v1[0]['operate_time']);
            $arr1[$key]['created_at'] = $v1[0]['created_at'];
            $arr1[$key]['nickname'] = $v1[0]['nickname'];
            $arr1[$key]['purchase_no'] = $v1[0]['purchase_no'];
            $arr1[$key]['all_id_type'] = $v1[0]['all_id_type'];
            $arr1[$key]['all_id'] = $v1[0]['all_id'];
            $arr1[$key]['id'] = $v1[0]['id'];
            $arr1[$key]['supplier_id'] = $v1[0]['supplier_id'];
            $arr1[$key]['goods_cost'] = $v1[0]['materiel_mean_cost'];
            $arr1[$key]['sell_price'] = $v1[0]['sell_price'];
            $cancelSign = 1;
            foreach ($v1 as $v2) {
                $arr1[$key]['content'][] = [
                    'materiel_name' => $v2['materiel_name'],
                    'type_name' => $v2['type_name'],
                    'materiel_no' => $v2['materiel_no'],
                    'storage_name' => $v2['storage_name'],
                    'storage_address' => $v2['storage_address'],
                    'next_storage_name' => $v2['next_storage_name'],
                    'next_storage_address' => $v2['next_storage_address'],
                    'last_storage_num' => $v2['last_storage_num'],
                    'operate_num' => $v2['operate_num'],
                    'next_storage_num' => $v2['next_storage_num'],
                    'serial_number' => $v2['serial_number'],
                    'remark' => $v2['remark'],
                    'label_name' => $v2['label_name'],
                    'shelf_name' => $v2['shelf_name'],
                    'location_name' => $v2['location_name'],
                    'sell_price' => !empty($v2['sell_price']) ? $v2['sell_price'] : '',
                    'goods_cost' => !empty($v2['materiel_mean_cost']) ? $v2['materiel_mean_cost'] : '',
                ];

                if (!$v2['is_cancel']) {
                    $cancelSign = 0;
                }
            }
            $arr1[$key]['is_cancel'] = $cancelSign;
        }

        //撤销状态;0:未撤销;1:已撤销;
        if ($data['status']) {
            foreach ($arr1 as $k3 => $v3) {
                if (!$v3['is_cancel']) {
                    unset($arr1[$k3]);
                }
            }
        } else {
            foreach ($arr1 as $k3 => $v3) {
                if ($v3['is_cancel']) {
                    unset($arr1[$k3]);
                }
            }
        }

        return $arr1;
    }

    public static function inStorageExportData($data, $keywordCondition)
    {
        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['a.user_id'] = ['EQ' => $data['user_id']];
            }
        }
        $condition = [];
        switch ($data['log_type']) {
            case 1://报溢入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 1];
                break;
            case 2://退货入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 2];
                break;
            case 3://采购入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 4://生产订单入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 5://调拨入库
                $condition['type'] = ['EQ' => 1];
                break;
            case 6://直接入库
                $condition['type'] = ['EQ' => 2];
                break;
            case 7://生产订单还库
                $condition['type'] = ['EQ' => 3];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 8://扫码入库
                $condition['type'] = ['EQ' => 4];
                break;
            case 9://套件返仓
                $condition['type'] = ['EQ' => 5];
                break;
        }

        $query = LogInstorageModel::select(
            'a.id',
            'a.type',
            'a.storage_name',
            'a.storage_address',
            'last_storage_name as next_storage_name',
            'last_storage_address as next_storage_address',
            /* 'b.class_name as second_class_name',
             'b.class_no as second_class_no',
             'c.class_name as first_class_name',
             'c.class_no as first_class_no',*/
            'e.materiel_name',
            'e.type_name',
            'e.materiel_unit',
            'e.is_product_materiel',
            'e.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.is_cancel',
            'a.in_storage_time as operate_time',
            'a.purchase_no',
            /*'c.class_name',
            'c.class_no',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',*/
            'd.username',
            'd.nickname',
            'h.location_name',
            'i.shelf_name',
            'a.serial_number',
            'a.created_at',
            'a.user_id',
            'a.main_id',
            'a.is_cancel',
            'a.all_id',
            'a.all_id_type',
            'a.label_name',
            'a.supplier_id',
            'e.selling_price as sell_price',
        )
            ->from('log_instorage as a')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage_shelf_location as h', 'h.id', '=', 'a.location_id')
            ->leftJoin('storage_shelf as i', 'i.id', '=', 'a.shelf_id')
            ->where($condition)
            ->where($operateCondition)
            ->where([
                'a.delete_flag'=> 0,
                ['a.type', '!=', 7],
                ['a.all_id_type', '!=', 8],
            ]);

        if ($data['materiel_class_id'] != 0) {
            $query->where('a.materiel_class_id', $data['materiel_class_id']);
        }

        if (!empty($data['label_id'])) {
            $query->where('a.label_id', $data['label_id']);
        }

        $keyword = empty($data['keyword']) ? '' : $data['keyword'];

        if (!empty($data['start_time'])) {
            $startTimeArr = explode(' ', $data['start_time']);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($data['end_time'])) {
            $endTimeArr = explode(' ', $data['end_time']);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query->whereBetween('in_storage_time', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query->where('in_storage_time', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query->where('in_storage_time', '<=', $endTime);
        }

        $query = $query->where(function ($query) use ($keywordCondition, $data) {
            if (!empty($keywordCondition)) {
                $query->orWhere($keywordCondition);
//            if($data['type'] == 0) {
//                $query->orWhere('purchase_no', 'like', '%'.$data['keyword'].'%');
//            }
            }
        })
            ->orderBy('a.id', 'desc')
            ->get();
        $query = !empty($query) ? $query->toArray() : [];
        return self::exportDataAssignList($data, $query);
    }

    public static function inGoodsExportData($data, $keywordCondition)
    {
        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['a.user_id'] = ['EQ' => $data['user_id']];
            }
        }

        $condition = [];
        switch ($data['log_type']) {
            case 1://报溢入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 1];
                break;
            case 2://退货入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 2];
                break;
            case 3://采购入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 4://生产订单入库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 5://调拨入库
                $condition['type'] = ['EQ' => 1];
                break;
            case 6://直接入库
                $condition['type'] = ['EQ' => 2];
                break;
            case 7://生产订单还库
                $condition['type'] = ['EQ' => 3];
                $condition['all_id_type'] = ['EQ' => 4];
                break;
            case 8://扫码入库
                $condition['type'] = ['EQ' => 4];
                break;
            case 9://套件返仓
                $condition['type'] = ['EQ' => 5];
                break;
        }
        $query = LogInstorageModel::query()->select(
            'a.id',
            'b.materiel_name',
            'b.type_name',
            'b.materiel_unit',
            'a.supplier_id',
            'a.materiel_type_id',
            'c.name',
            DB::raw('SUM(operate_num) AS total_num')
        )->from('log_instorage as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.materiel_type_id')
            ->leftJoin('supplier_customer as c', 'c.id', '=', 'a.supplier_id')
            ->where($condition)
            ->where($operateCondition)
            ->where([
                'a.delete_flag' => 0,
                ['supplier_id', '>', 0]
            ])->where(function ($query) use ($data, $keywordCondition) {
                if ($data['materiel_class_id'] != 0) {
                    $query->where('a.materiel_class_id', $data['materiel_class_id']);
                }
                if (!empty($data['label_id'])) {
                    $query->where('a.label_id', $data['label_id']);
                }
                if (!empty($data['start_time'])) {
                    $startTimeArr = explode(' ', $data['start_time']);
                    $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
                }
                if (!empty($data['end_time'])) {
                    $endTimeArr = explode(' ', $data['end_time']);
                    $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
                }
                if (!empty($startTime) && !empty($endTime)) {
                    $query->whereBetween('in_storage_time', [$startTime, $endTime]);
                } else if (!empty($startTime) && empty($endTime)) {
                    $query->where('in_storage_time', '>=', $startTime);
                } else if (empty($startTime) && !empty($endTime)) {
                    $query->where('in_storage_time', '<=', $endTime);
                }
                if (!empty($keywordCondition)) {
                    $query->orWhere($keywordCondition);
                }
            });
        $list = $query->groupBy(['supplier_id', 'materiel_type_id'])
            ->orderBy('a.id', 'desc')->get()->toArray();
        $supplierArr = [];
        if (!empty($list)) {
            foreach ($list as $iVal) {
                $supplierArr[] = [
                    'supplier_id' => $iVal['supplier_id'],
                    'supplier_name' => $iVal['name'],
                ];
            }
            $supplierArr = array_map("unserialize", array_unique(array_map("serialize", $supplierArr)));
            foreach ($supplierArr as &$val) {
                foreach ($list as $lVal) {
                    if ($val['supplier_id'] === $lVal['supplier_id']) {
                        $val['goods_list'][] = $lVal;
                    }
                }
            }
        }
        return $supplierArr;
    }


    public static function outStorageExportData($data, $keywordCondition)
    {
        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['a.user_id'] = ['EQ' => $data['user_id']];
            }
        }

        $condition = [];
        switch ($data['log_type']) {
            case 1://报损出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 1];
                break;
            case 2://销售出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 2];
                break;
            case 3://生产订单出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 4://调拨出库
                $condition['type'] = ['EQ' => 1];
                break;
            case 5://直接出库
                $condition['type'] = ['EQ' => 2];
                break;
            case 6://生产订单补足
                $condition['type'] = ['EQ' => 3];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 7://扫码出库
                $condition['type'] = ['EQ' => 4];
                break;
            case 8://套餐拆解
                $condition['type'] = ['EQ' => 5];
                break;
        }
//        }
        $query = LogOutstorageModel::query()->select(
            'a.id',
            'a.type',
            'a.storage_name',
            'a.storage_address',
            'a.next_storage_name',
            'a.next_storage_address',
            'e.materiel_name',
            'e.type_name',
            'e.materiel_no',
            'e.materiel_unit',
            'e.is_product_materiel',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.is_cancel',
            'a.out_storage_time as operate_time',
            'a.purchase_no',
            'a.label_name',
            'd.username',
            'a.main_id',
            'a.created_at',
            'd.nickname',
            'a.all_id',
            'a.all_id_type',
            'h.location_name',
            'i.shelf_name',
            'a.serial_number',
            'a.sell_price',
            'a.client_id as supplier_id'
        )
            ->from('log_outstorage as a')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.materiel_type_id')
            /* ->leftJoin('storage as f', 'f.id', '=', 'a.storage_id')
             ->leftJoin('storage as g', 'g.id', '=', 'a.next_storage_id')*/
            ->leftJoin('storage_shelf_location as h', 'h.id', '=', 'a.location_id')
            ->leftJoin('storage_shelf as i', 'i.id', '=', 'a.shelf_id')
            ->where($operateCondition)
            ->where([
                'a.delete_flag' => 0,
                ['a.type', '!=', 8],
                ['a.all_id_type', '!=', 5]
            ]);

        if (!empty($condition)) {
            $query->where($condition);
        }
        if ($data['materiel_class_id'] != 0) {
            $query->where('a.materiel_class_id', $data['materiel_class_id']);
        }
        if (!empty($data['f_class_id'])) {
            $classIdArr = MaterielClassModel::query()
                ->where([
                    'parent_id' => $data['f_class_id'],
                    'delete_flag' => 0,
                    'main_id' => $data['main_id']
                ])->pluck('id')->toArray();
            if (!empty($classIdArr)) {
                $query->whereIn('a.materiel_class_id', $classIdArr);
            }
        }
        if (!empty($data['label_id'])) {
            $query->where('a.label_id', $data['label_id']);
        }

        $keyword = empty($data['keyword']) ? '' : $data['keyword'];

        if (!empty($data['start_time'])) {
            $startTimeArr = explode(' ', $data['start_time']);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($data['end_time'])) {
            $endTimeArr = explode(' ', $data['end_time']);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query->whereBetween('out_storage_time', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query->where('out_storage_time', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query->where('out_storage_time', '<=', $endTime);
        }

        $query = $query->where(function ($query) use ($keywordCondition, $data) {
            if (!empty($keywordCondition)) {
                $query->orWhere($keywordCondition);
            }
        })
            ->orderBy('a.id', 'desc')
            ->get();
        $query = !empty($query) ? $query->toArray() : [];

        return self::exportDataAssignList($data, $query);
    }

    public static function outGoodsExportData($data, $keywordCondition)
    {
        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['a.main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['a.user_id'] = ['EQ' => $data['user_id']];
            }
        }

        $condition = [];
        switch ($data['log_type']) {
            case 1://报损出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 1];
                break;
            case 2://销售出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 2];
                break;
            case 3://生产订单出库
                $condition['type'] = ['EQ' => 0];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 4://调拨出库
                $condition['type'] = ['EQ' => 1];
                break;
            case 5://直接出库
                $condition['type'] = ['EQ' => 2];
                break;
            case 6://生产订单补足
                $condition['type'] = ['EQ' => 3];
                $condition['all_id_type'] = ['EQ' => 3];
                break;
            case 7://扫码出库
                $condition['type'] = ['EQ' => 4];
                break;
            case 8://套餐拆解
                $condition['type'] = ['EQ' => 5];
                break;
        }
//        }
        $query = LogOutstorageModel::query()->select(
            'a.id',
            'b.materiel_name',
            'b.type_name',
            'b.materiel_no',
            'b.materiel_unit',
            'a.operate_num',
            'a.client_id as supplier_id',
            'name',
            DB::raw('SUM(operate_num) AS total_num')
        )->from('log_outstorage as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.materiel_type_id')
            ->leftJoin('supplier_customer as c', 'c.id', '=', 'a.client_id')
            ->where([
                'a.delete_flag' => 0,
                ['client_id', '>', 0]
            ])
            ->where($operateCondition)
            ->where(function ($query) use ($data, $condition, $keywordCondition) {
                if (!empty($condition)) {
                    $query->where($condition);
                }
                if ($data['materiel_class_id'] != 0) {
                    $query->where('a.materiel_class_id', $data['materiel_class_id']);
                }
                if (!empty($data['f_class_id'])) {
                    $classIdArr = MaterielClassModel::query()
                        ->where([
                            'parent_id' => $data['f_class_id'],
                            'delete_flag' => 0,
                            'main_id' => $data['main_id']
                        ])->pluck('id')->toArray();
                    if (!empty($classIdArr)) {
                        $query->whereIn('a.materiel_class_id', $classIdArr);
                    }
                }
                if (!empty($data['label_id'])) {
                    $query->where('a.label_id', $data['label_id']);
                }


                if (!empty($data['start_time'])) {
                    $startTimeArr = explode(' ', $data['start_time']);
                    $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
                }

                if (!empty($data['end_time'])) {
                    $endTimeArr = explode(' ', $data['end_time']);
                    $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
                }

                if (!empty($startTime) && !empty($endTime)) {
                    $query->whereBetween('out_storage_time', [$startTime, $endTime]);
                } else if (!empty($startTime) && empty($endTime)) {
                    $query->where('out_storage_time', '>=', $startTime);
                } else if (empty($startTime) && !empty($endTime)) {
                    $query->where('out_storage_time', '<=', $endTime);
                }

                if (!empty($keywordCondition)) {
                    $query->orWhere($keywordCondition);
                }
            });
        $list = $query->groupBy(['client_id', 'materiel_type_id'])
            ->orderBy('a.id', 'desc')->get()->toArray();
        $supplierArr = [];
        if (!empty($list)) {
            foreach ($list as $iVal) {
                $supplierArr[] = [
                    'supplier_id' => $iVal['supplier_id'],
                    'supplier_name' => $iVal['name'],
                ];
            }
            $supplierArr = array_map("unserialize", array_unique(array_map("serialize", $supplierArr)));
            foreach ($supplierArr as &$val) {
                foreach ($list as $lVal) {
                    if ($val['supplier_id'] === $lVal['supplier_id']) {
                        $val['goods_list'][] = $lVal;
                    }
                }
            }
        }
        return $supplierArr;

    }

    static public function packageOutstorageList($data)
    {
        $keyword = empty($data['keyword']) ? '' : $data['keyword'];

        $operateCondition = [];
        if ($data['user_id'] == $data['main_id']) {
            $operateCondition['main_id'] = ['EQ' => $data['main_id']];
        } else {
            if ($data['is_share_log']) {
                $operateCondition['main_id'] = ['EQ' => $data['main_id']];
            } else {
                $operateCondition['user_id'] = ['EQ' => $data['user_id']];
            }
        }

        //根据是否共享操作记录找到对应的出库信息id
        $operateSearchLogStorageData = LogPackageModel::select('id')->where($operateCondition)->get()->toArray();

        $logId = [];
        foreach ($operateSearchLogStorageData as $value) {
            $logId[] = $value['id'];
        }

//        if($data['is_share_storage']) {
        $storageInfo = StorageModel::select('id')->where('user_id', $data['user_id'])->get()->toArray();

        $storageId = [];
        foreach ($storageInfo as $value) {
            $storageId[] = $value['id'];
        }

        //仓库共享开启后，获取自己所负责的仓库信息用于查找他人操作我的仓库的进出库记录-普通入库
        $storageSearchLogStorageData = LogPackageContentModel::select('log_package_id')->whereIn('storage_id', $storageId)->get()->toArray();

        if (!empty($storageSearchLogStorageData)) {
            foreach ($storageSearchLogStorageData as $v1) {
                if (!in_array($v1['log_package_id'], $logId)) {
                    $logId[] = $v1['log_package_id'];
                }
            }
        }
//        }

        $query = LogPackageModel::select(
            'a.id',
            'a.package_name',
            'a.num',
            'a.remark',
            'a.is_cancel',
            'a.created_at',
            'username',
            'nickname',
            'd.location_name',
            'e.shelf_name',
            'c.serial_number'
        )
            ->from('log_package as a')
            ->leftJoin('admin as b', 'b.id', '=', 'a.user_id')
            ->leftJoin('log_package_content as c', 'c.log_package_id', '=', 'a.id')
            ->leftJoin('storage_shelf_location as d', 'd.id', '=', 'c.location_id')
            ->leftJoin('storage_shelf as e', 'e.id', '=', 'c.shelf_id')
            ->where('a.delete_flag', 0)
            ->where('a.is_cancel', $data['status']);

        if (!empty($data['start_time'])) {
            $startTimeArr = explode(' ', $data['start_time']);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($data['end_time'])) {
            $endTimeArr = explode(' ', $data['end_time']);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query->whereBetween('a.created_at', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query->where('a.created_at', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query->where('a.created_at', '<=', $endTime);
        }

        $query->where(function ($query) use ($keyword) {
            $query->orWhere('package_name', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_name', 'like', '%' . $keyword . '%');
            $query->orWhere('type_name', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_no', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_class_name', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_class_no', 'like', '%' . $keyword . '%');
        });

        return $query->whereIn('a.id', $logId)->orderBy('a.id', 'desc')
            ->groupBy('a.id')
            ->paginate($data['pageSize'], ['*'], '', $data['currentPage'])->toArray();
    }

    static public function cancelAllocateOut($data)
    {
        $info = LogOutStorageModel::where('id', $data['id'])->first();

        if ($info['is_cancel']) {
            return ['code' => 1, 'msg' => '当前记录已经撤销，无法重复操作', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            if (!empty($info['serial_number'])) {
                self::cancelSerialAllocateOut($info);
            } else {
                if (!empty($info['before_allocate_batch_id'])) {
                    self::cancelBatchAllocateOut($info);
                } else {
                    self::cancelNormalAllocateOut($info);
                }
            }

            $info->is_cancel = 1;
            $info->save();

            LogInStorageModel::where('id', $info['log_in_id'])
                ->update([
                    'is_cancel' => 1
                ]);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        } catch (Exception $e) {
            DB::rollBack();
            Log::debug('调拨入库撤销异常:' . var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    static private function cancelNormalAllocateOut($info)
    {
        $outstorageInfo = StorageManageModel::where('id', $info['next_storage_manage_id'])->first();

        if ($outstorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if ($outstorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $outstorageInfo->in_storage_num = $outstorageInfo->in_storage_num - $info['operate_num'];
        $outstorageInfo->virtual_storage_num = $outstorageInfo->virtual_storage_num - $info['operate_num'];
        $outstorageInfo->save();

        StorageManageModel::where('id', $info['curr_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('in_storage_num + ' . $info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'delete_flag' => 0
            ]);

        StorageBatchModel::where('id', $info['curr_storage_manage_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + ' . $info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + ' . $info['operate_num']),
            ]);
//
//        LogInStorageModel::where([
//            'type' => 1,
//            'last_storage_manage_id' => $info['curr_storage_manage_id'],
//            'curr_storage_manage_id' => $info['next_storage_address'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    static private function cancelBatchAllocateOut($info)
    {
        $outstorageInfo = StorageManageModel::where('id', $info['next_storage_manage_id'])->first();

        if ($outstorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if ($outstorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $outstorageInfo->in_storage_num = $outstorageInfo->in_storage_num - $info['operate_num'];
        $outstorageInfo->virtual_storage_num = $outstorageInfo->virtual_storage_num - $info['operate_num'];
        $outstorageInfo->save();

        StorageManageModel::where('id', $info['curr_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'delete_flag' => 0
            ]);

        $inBatchInfo = StorageBatchModel::where('id', $info['storage_batch_id'])->first();

        if ($inBatchInfo['batch_left_num'] < $info['operate_num']) {
            throw new Exception('调拨后的批次数量不足，无法完成调拨撤销，当前剩余可撤销批次数量为:' . $inBatchInfo['batch_left_num']);
        }

        $inBatchInfo->batch_left_num = $inBatchInfo->batch_left_num - $info['operate_num'];
        $inBatchInfo->batch_num = $inBatchInfo->batch_num - $info['operate_num'];
        $inBatchInfo->save();

        StorageBatchModel::where('id', $info['before_allocate_batch_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + ' . $info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + ' . $info['operate_num']),
            ]);

//        LogInStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['next_storage_manage_id'],
//            'last_storage_manage_id' => $info['curr_storage_manage_id'],
//            'before_allocate_batch_id' => $info['before_allocate_batch_id'],
//            'storage_batch_id' => $info['batch_id'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    static protected function cancelSerialAllocateOut($info)
    {
        $outstorageInfo = StorageManageModel::where('id', $info['next_storage_manage_id'])->first();

        if ($outstorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if ($outstorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $serialNo = array_filter(explode(',', $info['serial_number']), function ($v) {
            return $v !== '';
        });
        $outstorageSerialInfo = SerialNumberModel::where([
            'storage_manage_id' => $info['next_storage_manage_id']
        ])->where(['delete_flag' => 0])
            ->whereIn('serial_no', $serialNo)
            ->get()->toArray();
        $serialInfo = [];
        foreach ($outstorageSerialInfo as $val) {
            if (!$val['status']) {
                throw new Exception('序列号:' . $val['serial_no'] . '已被使用，无法撤销');
            }

            $serialInfo[] = [
                'id' => $val['id'],
                'storage_manage_id' => $info['curr_storage_manage_id']
            ];
        }

        if (!empty($serialInfo)) {
            batch()->update(new SerialNumberModel, $serialInfo, 'id');
        }


//        $outstorageSerialInfo = SerialNumberModel::where([
//            'storage_manage_id' => $info['next_storage_manage_id'],
//            'serial_no' => $info['serial_number'],
//        ])->first();
//
//        if($outstorageSerialInfo['status'] == 0) {
//            throw new Exception('序列号:'.$outstorageInfo['serial_no'].'已被使用，无法撤销');
//        }

        $outstorageInfo->in_storage_num = $outstorageInfo->in_storage_num - $info['operate_num'];
        $outstorageInfo->virtual_storage_num = $outstorageInfo->virtual_storage_num - $info['operate_num'];
        $outstorageInfo->save();

//        $outstorageSerialInfo->storage_manage_id = $info['curr_storage_manage_id'];
//        $outstorageSerialInfo->save();

        StorageManageModeL::where([
            'id' => $info['curr_storage_manage_id']
        ])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'delete_flag' => 0
            ]);

        return true;
    }

    /**
     * 调拨撤销调入侧
     * @param $data
     * 2022/9/30 17:17
     * Author: Sun Wu
     * @return array
     */
    static public function cancelAllocateIn($data)
    {
        $info = LogInStorageModel::where('id', $data['id'])->first();
//
//        if($info['is_cancel']) {
//            return ['code' => 1, 'msg' => '当前记录已经撤销，无法重复操作', 'data' => ''];
//        }

        DB::beginTransaction();

        try {
            if (!empty($info['serial_number'])) {
                self::cancelSerialAllocateIn($info);
            } else {
                if (!empty($info['before_allocate_batch_id'])) {
                    self::cancelBatchAllocateIn($info);
                } else {
                    self::cancelNormalAllocateIn($info);
                }
            }

            $info->is_cancel = 1;
            $info->save();

            LogOutStorageModel::where('id', $info['log_out_id'])
                ->update([
                    'is_cancel' => 1
                ]);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        } catch (Exception $e) {
            DB::rollBack();
            Log::debug('调拨入库撤销异常:' . var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    /**
     * @throws Exception
     */
    static protected function cancelNormalAllocateIn($info)
    {
        $instorageInfo = StorageManageModel::where('id', $info['curr_storage_manage_id'])->first();

        if ($instorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if ($instorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $instorageInfo->in_storage_num = $instorageInfo->in_storage_num - $info['operate_num'];
        $instorageInfo->virtual_storage_num = $instorageInfo->virtual_storage_num - $info['operate_num'];
        $instorageInfo->save();

        StorageManageModel::where('id', $info['last_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('in_storage_num +' . $info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num +' . $info['operate_num']),
                'delete_flag' => 0
            ]);

        StorageBatchModel::where('id', $info['before_allocate_batch_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + ' . $info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + ' . $info['operate_num']),
            ]);

//        LogOutStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['last_storage_manage_id'],
//            'next_storage_manage_id' => $info['curr_storage_manage_id'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    /**
     * 批次调拨撤销
     * @param $info
     * 2022/9/30 17:08
     * Author: Sun Wu
     * @return bool
     */
    static protected function cancelBatchAllocateIn($info)
    {
        $instorageInfo = StorageManageModel::where('id', $info['curr_storage_manage_id'])->first();

        if ($instorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if ($instorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $instorageInfo->in_storage_num = $instorageInfo->in_storage_num - $info['operate_num'];
        $instorageInfo->virtual_storage_num = $instorageInfo->virtual_storage_num - $info['operate_num'];
        $instorageInfo->save();

        StorageManageModel::where('id', $info['last_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'delete_flag' => 0
            ]);

        $inBatchInfo = StorageBatchModel::where('id', $info['batch_id'])->first();

        if ($inBatchInfo['batch_left_num'] < $info['operate_num']) {
            throw new Exception('调拨后的批次数量不足，无法完成调拨撤销，当前剩余可撤销批次数量为:' . $inBatchInfo['batch_left_num']);
        }

        $inBatchInfo->batch_left_num = $inBatchInfo->batch_left_num - $info['operate_num'];
        $inBatchInfo->batch_num = $inBatchInfo->batch_num - $info['operate_num'];
        $inBatchInfo->save();

        StorageBatchModel::where('id', $info['before_allocate_batch_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + ' . $info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + ' . $info['operate_num']),
            ]);

//        LogOutStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['last_storage_manage_id'],
//            'next_storage_manage_id' => $info['curr_storage_manage_id'],
//            'before_allocate_batch_id' => $info['before_allocate_batch_id'],
//            'storage_batch_id' => $info['batch_id'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    /**
     * 序列号调入撤销
     * @param $info
     * 2022/9/30 16:07
     * Author: Sun Wu
     * @return bool
     */
    static protected function cancelSerialAllocateIn($info)
    {
        $instorageInfo = StorageManageModel::where('id', $info['curr_storage_manage_id'])->first();

        if ($instorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if ($instorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $serialNo = array_filter(explode(',', $info['serial_number']), function ($v) {
            return $v !== '';
        });
        $instorageSerialInfo = SerialNumberModel::where([
            'storage_manage_id' => $info['curr_storage_manage_id']
        ])->where(['delete_flag' => 0])
            ->whereIn('serial_no', $serialNo)
            ->get()->toArray();

        $serialInfo = [];
        foreach ($instorageSerialInfo as $val) {
            if (!$val['status']) {
                throw new Exception('序列号:' . $val['serial_no'] . '已被使用，无法撤销');
            }

            $serialInfo[] = [
                'id' => $val['id'],
                'storage_manage_id' => $info['last_storage_manage_id']
            ];
        }

        if (!empty($serialInfo)) {
            batch()->update(new SerialNumberModel, $serialInfo, 'id');
        }

        $instorageInfo->in_storage_num = $instorageInfo->in_storage_num - $info['operate_num'];
        $instorageInfo->virtual_storage_num = $instorageInfo->virtual_storage_num - $info['operate_num'];
        $instorageInfo->save();

//        $instorageSerialInfo->storage_manage_id = $info['last_storage_manage_id'];
//        $instorageSerialInfo->save();

        StorageManageModel::where('id', $info['last_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + ' . $info['operate_num']),
                'delete_flag' => 0
            ]);

        $inBatchInfo = StorageBatchModel::where('id', $info['batch_id'])->first();

        if (!empty($inBatchInfo)) {
            //撤销调入产生的批次信息
            if ($inBatchInfo['batch_left_num'] > 0) {
                $inBatchInfo->batch_left_num = $inBatchInfo->batch_left_num - $info['operate_num'];
                $inBatchInfo->save();
            } else {
                //调入产生的批次信息数量不足，找到批次数量最大的批次抵扣一次
                $findInbatchInfo = StorageBatchModel::where('storage_manage_id', $info['curr_storage_manage_id'])
                    ->orderBy('batch_left_num', 'desc')
                    ->first();

                if ($findInbatchInfo['batch_left_num'] > 0) {
                    $findInbatchInfo->batch_num = $findInbatchInfo->batch_num - $info['operate_num'];
                    $findInbatchInfo->batch_left_num = $findInbatchInfo->batch_left_num - $info['operate_num'];
                    $findInbatchInfo->save();
                } else {
                    //以上条件未满足时，将调入的批次删除
                    $inBatchInfo->delete_flag = 1;
                    $inBatchInfo->save();
                }
            }
        }
//
//        LogOutStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['last_storage_manage_id'],
//            'next_storage_manage_id' => $info['curr_storage_manage_id'],
//            'serial_number' => $info['serial_number'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    //撤销直接入库
    static public function cancelDirectInstorage($data): array
    {
        $basicLogInfo = LogInstorageModel::where([
            'id' => $data['id'],
            'main_id' => $data['main_id']
        ])->first()->toArray();

        if (empty($basicLogInfo)) {
            return ['code' => 1, 'msg' => '无效操作记录', 'data' => ''];
        }

        if (!in_array($basicLogInfo['all_id_type'], [0, 10])) {
            return ['code' => 1, 'msg' => '不支持的可撤销记录类型', 'data' => ''];
        }
        $logGroup = LogInStorageModel::query()->where([
            'created_at' => strtotime($basicLogInfo['created_at']),
            'type' => $basicLogInfo['type'],
            'main_id' => $basicLogInfo['main_id'],
            'delete_flag' => 0,
            'is_cancel' => 0
        ])->where(function ($query) {
            if (!empty($basicLogInfo['code_allocate_no'])) {
                $query->where('code_allocate_no', $basicLogInfo['code_allocate_no']);
            }
        })->get();

        if (!empty($logGroup->toArray())) {
            $logGroup = $logGroup->toArray();
            switch ($basicLogInfo['type']) {
                case 2://新建入库
                case 4://扫码入库
                    self::cancelDirectInStorageCommon($logGroup);
                    break;
                case 1://调拨入库
                    self::cancelAllocateInCommon($basicLogInfo, $logGroup);
                    break;
                case 9://扫码调拨入库
                    $outLogGroup = LogOutStorageModel::query()->where([
                        'created_at' => strtotime($basicLogInfo['created_at']),
                        'type' => 8,
                        'main_id' => $basicLogInfo['main_id'],
                        'delete_flag' => 0,
                        'is_cancel' => 0,
                        'code_allocate_no' => $basicLogInfo['code_allocate_no']
                    ])->get();
                    $outLogGroup = !empty($outLogGroup->toArray()) ? $outLogGroup->toArray() : [];
                    self::cancelCodeAllocateInCommon($basicLogInfo, $logGroup, $outLogGroup);
                    break;
            }

            //变更入库记录为已撤销
            LogInStorageModel::where([
                'created_at' => strtotime($basicLogInfo['created_at']),
                'type' => $basicLogInfo['type'],
                'main_id' => $basicLogInfo['main_id'],
                'delete_flag' => 0,
                'is_cancel' => 0
            ])->update(['is_cancel' => 1]);
            $basicLogInfo['type'] = 7;
            $basicLogInfo['all_id_type'] = 8;
            $basicLogInfo['front_in_log_id'] = $basicLogInfo['id'];
            $basicLogInfo['created_at'] = $data['logTime'];
            $basicLogInfo['in_storage_time'] = $data['logTime'];
            unset($basicLogInfo['id']);
            LogInStorageModel::insertGetId($basicLogInfo);
        }
        //日志类型;0:入库;1:调拨入库;2:直接入库;3生产订单还库;4:扫码入库;5:套件返仓;6导入入库;7撤销还库
        $logReg = "入库";
        if ($basicLogInfo['type'] == 2) {
            $logReg = '直接入库';
        } elseif ($basicLogInfo['type'] == 1) {
            $logReg = '调拨入库';
        } elseif ($basicLogInfo['type'] == 4) {
            $logReg = '扫码入库';
        } elseif ($basicLogInfo['type'] == 9) {
            $logReg = '扫码调拨入库';
        }
        CommonService::operateResult($data['user_id'], $data['logTime'], $data, $logReg . ',撤销成功！');
        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    private static function cancelAllocateInCommon($basicLogInfo, $logGroup)
    {
        $storageManageBeforeData = [];
        $storageManageAfterData = [];
        $serialData = [];
        foreach ($logGroup as $value) {
            //调拨后库存信息
            $storageManageNextInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();

            //调拨前库存信息
            $storageManageBeforeInfo = StorageManageModel::where([
                'id' => $value['last_storage_manage_id'],
            ])->first();


            if ($storageManageNextInfo['delete_flag']) {
                throw new Exception('商品:' . $storageManageNextInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }

            /*  if($storageManageNextInfo['virtual_storage_num'] < $value['operate_num']) {
                  throw new Exception('商品:'.$storageManageNextInfo['materiel_name'].'可撤销数量(X'.$storageManageNextInfo['virtual_storage_num'].')不足,撤销数量:'.$value['operate_num']);
              }*/
            if (!OperMainAccountModel::query()
                ->where([
                    'main_id' => $storageManageNextInfo['main_id'],
                    'delete_flag' => 0
                ])->exists()) {
                if ($storageManageNextInfo['in_storage_num'] < $value['operate_num']) {
                    throw new Exception('商品:' . $storageManageNextInfo['materiel_name'] . '实际库存数量(X' . $storageManageNextInfo['in_storage_num'] . ')不足,撤销数量:' . $value['operate_num']);
                }
            }
            //调拨后库存数量扣除
            $storageManageBeforeData[] = [
                'id' => $value['curr_storage_manage_id'],
                'in_storage_num' => $storageManageNextInfo['in_storage_num'] - $value['operate_num'],
                //'virtual_storage_num' => $storageManageNextInfo['virtual_storage_num'] - $value['operate_num'],
            ];

            //调拨前库存数量增加
            $storageManageAfterData[] = [
                'id' => $value['last_storage_manage_id'],
                'in_storage_num' => $storageManageBeforeInfo['in_storage_num'] + $value['operate_num'],
                //'virtual_storage_num' => $storageManageBeforeInfo['virtual_storage_num'] + $value['operate_num'],
            ];

            //调拨时序列号处理
            if (!empty($value['serial_number'])) {
                $serialNumberInfo = array_filter(explode(',', $value['serial_number']), function ($v) {
                    return $v !== '';
                });

                foreach ($serialNumberInfo as $serialValue) {
                    $singleSerialInfo = SerialNumberModel::where([
                        'goods_id' => $value['materiel_type_id'],
                        'serial_no' => $serialValue,
                        'delete_flag' => 0
                    ])->first();
                    if (empty($singleSerialInfo)) {
                        throw new Exception('商品:' . $value['materiel_name'] . '序列号:' . $serialValue . '不存在，无法撤销');
                    }
                    $serialData[] = [
                        'goods_id' => $value['materiel_type_id'],
                        'id' => $singleSerialInfo['id'],
                        'storage_manage_id' => $value['last_storage_manage_id']
                    ];
                }
            }
        }

        if (!empty($storageManageBeforeData)) {
            batch()->update(new StorageManageModel, $storageManageBeforeData, 'id');
        }

        if (!empty($storageManageAfterData)) {
            batch()->update(new StorageManageModel, $storageManageAfterData, 'id');
        }

        if (!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        LogOutStorageModel::where('allocate_no', $basicLogInfo['allocate_no'])
            ->update(['is_cancel' => 1]);

        return true;
    }

    private static function cancelCodeAllocateInCommon($basicLogInfo, $logGroup, $outLogGroup)
    {
        $inData = [];
        $outData = [];
        $serialData = [];
        foreach ($logGroup as $value) {
            //调拨后库存信息
            $inManageInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();
            if (!empty($inManageInfo['delete_flag'])) {
                throw new \RuntimeException('商品:' . $inManageInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }
            if (!OperMainAccountModel::query()
                ->where([
                    'main_id' => $inManageInfo['main_id'],
                    'delete_flag' => 0
                ])->exists()) {
                if ($inManageInfo['in_storage_num'] < $value['operate_num']) {
                    throw new Exception('商品:' . $inManageInfo['materiel_name'] . '实际库存数量(X' . $inManageInfo['in_storage_num'] . ')不足,撤销数量:' . $value['operate_num']);
                }
            }
            //调拨后库存数量扣除
            $inData[] = [
                'id' => $value['curr_storage_manage_id'],
                'in_storage_num' => $inManageInfo['in_storage_num'] - $value['operate_num'],
            ];
            if (!empty($value['storage_batch_id'])) {
                StorageBatchModel::query()->where('id', $value['batch_id'])
                    ->decrement('batch_left_num', $value['operate_num']);
            }
        }
        if (!empty($outLogGroup)) {
            foreach ($outLogGroup as $value) {
                //调拨后库存信息
                $outManageInfo = StorageManageModel::where([
                    'id' => $value['curr_storage_manage_id'],
                ])->first();
                if ($outManageInfo['delete_flag']) {
                    throw new Exception('商品:' . $outManageInfo['materiel_name'] . '库存已被删除，无法完成撤销');
                }
                //调拨前库存数量增加
                $outData[] = [
                    'id' => $value['curr_storage_manage_id'],
                    'in_storage_num' => $outManageInfo['in_storage_num'] + $value['operate_num'],
                ];
                if (!empty($value['storage_batch_id'])) {
                    StorageBatchModel::query()->where('id', $value['storage_batch_id'])
                        ->increment('batch_left_num', $value['operate_num']);
                }
            }
        }
        if (!empty($inData)) {
            batch()->update(new StorageManageModel, $inData, 'id');
        }

        if (!empty($outData)) {
            batch()->update(new StorageManageModel, $outData, 'id');
        }
        LogOutStorageModel::where('code_allocate_no', $basicLogInfo['code_allocate_no'])
            ->update(['is_cancel' => 1]);
        return true;
    }

    private static function cancelDirectInStorageCommon($logGroup)
    {
        $storageManageData = [];
        $serialData = [];

        foreach ($logGroup as $value) {
            $storageManageInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();


            if ($storageManageInfo['delete_flag']) {
                throw new Exception('商品:' . $storageManageInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }

            /*if($storageManageInfo['virtual_storage_num'] < $value['operate_num']) {
                throw new Exception('商品:'.$storageManageInfo['materiel_name'].'可撤销数量(X'.$storageManageInfo['virtual_storage_num'].')不足,撤销数量:'.$value['operate_num']);
            }*/
            if (!OperMainAccountModel::query()
                ->where([
                    'main_id' => $storageManageInfo['main_id'],
                    'delete_flag' => 0
                ])->exists()) {
                if ($storageManageInfo['in_storage_num'] < $value['operate_num']) {
                    throw new Exception('商品:' . $storageManageInfo['materiel_name'] . '实际库存数量(X' . $storageManageInfo['in_storage_num'] . ')不足,撤销数量:' . $value['operate_num']);
                }
            }
            $storageManageData[] = [
                'id' => $value['curr_storage_manage_id'],
                'in_storage_num' => $storageManageInfo['in_storage_num'] - $value['operate_num'],
                ///'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $value['operate_num'],
            ];

            if (!empty($value['serial_number'])) {
                $serialNumberInfo = array_filter(explode(',', $value['serial_number']), function ($v) {
                    return $v !== '';
                });

                foreach ($serialNumberInfo as $serialValue) {
                    $singleSerialInfo = SerialNumberModel::where([
                        'goods_id' => $value['materiel_type_id'],
                        'serial_no' => $serialValue,
                        'delete_flag' => 0
                    ])->first();

                    if (empty($singleSerialInfo)) {
                        throw new Exception('商品:' . $value['materiel_name'] . '序列号:' . $serialValue . '不存在，无法撤销');
                    }

                    if ($singleSerialInfo['status'] == 0) {
                        throw new Exception('商品:' . $value['materiel_name'] . '序列号:' . $serialValue . '已被使用，无法撤销');
                    }

                    $serialData[] = [
                        'goods_id' => $value['materiel_type_id'],
                        'id' => $singleSerialInfo['id'],
                        'status' => 0
                    ];
                }
            }
        }

        if (!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        if (!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        return true;
    }

    //撤销-直接出库
    static public function cancelDirectOutstorage($data)
    {
        $basicLogInfo = LogOutstorageModel::where([
            'id' => $data['id'],
            'main_id' => $data['main_id']
        ])->first()->toArray();

        if (empty($basicLogInfo)) {
            return ['code' => 1, 'msg' => '无效操作记录', 'data' => ''];
        }

        if (!in_array($basicLogInfo['all_id_type'], [0, 11])) {
            return ['code' => 1, 'msg' => '不支持的可撤销记录类型', 'data' => ''];
        }

        $logGroup = LogOutstorageModel::query()->where([
            'created_at' => strtotime($basicLogInfo['created_at']),
            'type' => $basicLogInfo['type'],
            'main_id' => $basicLogInfo['main_id'],
            'delete_flag' => 0,
            'is_cancel' => 0
        ])->where(function ($query) {
            if (!empty($basicLogInfo['code_allocate_no'])) {
                $query->where('code_allocate_no', $basicLogInfo['code_allocate_no']);
            }
        })->get();

        if (!empty($logGroup)) {
            $logGroup = $logGroup->toArray();
            switch ($basicLogInfo['type']) {
                case 2:
                case 4:
                case 6:
                    self::cancelDirectOutstorageCommon($logGroup);
                    break;
                case 1:
                    self::cancelAllocateOutCommon($basicLogInfo, $logGroup);
                    break;
                case 11:
                    $inLogGroup = LogInStorageModel::query()->where([
                        'created_at' => strtotime($basicLogInfo['created_at']),
                        'type' => $basicLogInfo['type'],
                        'main_id' => $basicLogInfo['main_id'],
                        'delete_flag' => 0,
                        'is_cancel' => 0,
                        'code_allocate_no' => $basicLogInfo['code_allocate_no']
                    ])->get();
                    self::cancelCodeAllocateOutCommon($basicLogInfo, $logGroup, $inLogGroup);
                    break;
            }

            //变更入库记录为已撤销
            LogOutStorageModel::where([
                'created_at' => strtotime($basicLogInfo['created_at']),
                'type' => $basicLogInfo['type'],
                'main_id' => $basicLogInfo['main_id'],
                'delete_flag' => 0,
                'is_cancel' => 0
            ])->update(['is_cancel' => 1]);
            $basicLogInfo['type'] = 8;
            $basicLogInfo['all_id_type'] = 5;
            $basicLogInfo['front_out_log_id'] = $basicLogInfo['id'];
            $basicLogInfo['created_at'] = $data['logTime'];
            $basicLogInfo['out_storage_time'] = $data['logTime'];
            unset($basicLogInfo['id']);
            LogOutStorageModel::insertGetId($basicLogInfo);
        }
        $logReg = '出库';
        //type;0:出库;1:调出;2:直接出库;3:生产订单补足;4:扫码出库;5:套件拆解;6:老版本套餐出库;7导入出库;8撤销出库
        if ($basicLogInfo['type'] == 2) {
            $logReg = '直接出库';
        } elseif ($basicLogInfo['type'] == 1) {
            $logReg = '调拨出库';
        } elseif ($basicLogInfo['type'] == 4) {
            $logReg = '扫码出库';
        } elseif ($basicLogInfo['type'] == 6) {
            $logReg = '套餐出库';
        } elseif ($basicLogInfo['type'] == 11) {
            $logReg = '扫码调拨出库';
        }
        CommonService::operateResult($data['user_id'], $data['logTime'], $data, $logReg . ',撤销成功！');
        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    private static function cancelAllocateOutCommon($basicLogInfo, $logGroup)
    {
        $storageManageBeforeData = [];
        $storageManageAfterData = [];
        $serialData = [];

        foreach ($logGroup as $value) {
            $storageManageNextInfo = StorageManageModel::where([
                'id' => $value['next_storage_manage_id'],
            ])->first();

            $storageManageBeforeInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();

            if ($storageManageNextInfo['delete_flag']) {
                throw new Exception('商品:' . $storageManageNextInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }

            /* if ($value['operate_num'] > $storageManageNextInfo['virtual_storage_num']) {
                 throw new Exception('商品:' . $storageManageNextInfo['materiel_name'] . '可用库存数不足(实际可用库存:' . $storageManageNextInfo['virtual_storage_num'] . ',撤销数量:' . $value['operate_num'] . ')，无法完成撤销');
             }

             */
            if (!OperMainAccountModel::query()
                ->where([
                    'main_id' => $storageManageNextInfo['main_id'],
                    'delete_flag' => 0
                ])->exists()) {
                if ($value['operate_num'] > $storageManageNextInfo['in_storage_num']) {
                    throw new Exception('商品:' . $storageManageNextInfo['materiel_name'] . '库存数不足(实际库存:' . $storageManageNextInfo['in_storage_num'] . ',撤销数量:' . $value['operate_num'] . ')，无法完成撤销');
                }
            }
            $storageManageBeforeData[] = [
                'id' => $value['curr_storage_manage_id'],
                'in_storage_num' => $storageManageBeforeInfo['in_storage_num'] + $value['operate_num'],
                //'virtual_storage_num' => $storageManageBeforeInfo['virtual_storage_num'] + $value['operate_num'],
            ];

            $storageManageAfterData[] = [
                'id' => $value['next_storage_manage_id'],
                'in_storage_num' => $storageManageNextInfo['in_storage_num'] - $value['operate_num'],
                //'virtual_storage_num' => $storageManageNextInfo['virtual_storage_num'] - $value['operate_num'],
            ];

            if (!empty($value['serial_number'])) {
                $serialNumberInfo = array_filter(explode(',', $value['serial_number']), function ($v) {
                    return $v !== '';
                });

                foreach ($serialNumberInfo as $serialValue) {
                    $singleSerialInfo = SerialNumberModel::where([
                        'goods_id' => $value['materiel_type_id'],
                        'serial_no' => $serialValue,
                        'delete_flag' => 0
                    ])->first();
                    if (empty($singleSerialInfo)) {
                        throw new Exception('商品:' . $value['materiel_name'] . '序列号:' . $serialValue . '不存在，无法撤销');
                    }
                    if ($singleSerialInfo['status'] == 1) {
                        throw new Exception('商品:' . $value['materiel_name'] . '序列号:' . $serialValue . '未被使用，无法撤销');
                    }
                    $serialData[] = [
                        'goods_id' => $value['materiel_type_id'],
                        'id' => $singleSerialInfo['id'],
                        'storage_manage_id' => $value['curr_storage_manage_id']
                    ];
                }
            }
        }

        if (!empty($storageManageAfterData)) {
            batch()->update(new StorageManageModel, $storageManageAfterData, 'id');
        }

        if (!empty($storageManageBeforeData)) {
            batch()->update(new StorageManageModel, $storageManageBeforeData, 'id');
        }

        if (!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        LogInStorageModel::where('allocate_no', $basicLogInfo['allocate_no'])
            ->update(['is_cancel' => 1]);

        return true;
    }

    private static function cancelCodeAllocateOutCommon($basicLogInfo, $logGroup, $inLogGroup)
    {
        $inData = [];
        $outData = [];
        foreach ($logGroup as $value) {
            $outManageInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();
            if ($outManageInfo['delete_flag']) {
                throw new Exception('商品:' . $outManageInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }
            $outData[] = [
                'id' => $value['curr_storage_manage_id'],
                'in_storage_num' => $outManageInfo['in_storage_num'] + $value['operate_num'],
            ];
        }

        foreach ($inLogGroup as $value) {
            $inManageInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();
            if ($inManageInfo['delete_flag']) {
                throw new Exception('商品:' . $inManageInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }
            if (!OperMainAccountModel::query()
                ->where([
                    'main_id' => $inManageInfo['main_id'],
                    'delete_flag' => 0
                ])->exists()) {
                if ($value['operate_num'] > $inManageInfo['in_storage_num']) {
                    throw new Exception('商品:' . $inManageInfo['materiel_name'] . '库存数不足(实际库存:' . $inManageInfo['in_storage_num'] . ',撤销数量:' . $value['operate_num'] . ')，无法完成撤销');
                }
            }
            $inData[] = [
                'id' => $value['next_storage_manage_id'],
                'in_storage_num' => $inManageInfo['in_storage_num'] - $value['operate_num'],
            ];
        }

        if (!empty($outData)) {
            batch()->update(new StorageManageModel, $outData, 'id');
        }

        if (!empty($inData)) {
            batch()->update(new StorageManageModel, $inData, 'id');
        }
        LogInStorageModel::where('code_allocate_no', $basicLogInfo['code_allocate_no'])
            ->update(['is_cancel' => 1]);
        return true;
    }

    private static function cancelDirectOutstorageCommon($logGroup): bool
    {
        $storageManageData = [];
        $serialData = [];

        foreach ($logGroup as $value) {
            $storageManageInfo = StorageManageModel::where([
                'id' => $value['curr_storage_manage_id'],
            ])->first();

            if ($storageManageInfo['delete_flag']) {
                throw new Exception('商品:' . $storageManageInfo['materiel_name'] . '库存已被删除，无法完成撤销');
            }

            $storageManageData[] = [
                'id' => $value['curr_storage_manage_id'],
                'in_storage_num' => $storageManageInfo['in_storage_num'] + $value['operate_num'],
                //'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] + $value['operate_num'],
            ];

            if (!empty($value['serial_number'])) {
                $serialNumberInfo = array_filter(explode(',', $value['serial_number']), function ($v) {
                    return $v !== '';
                });

                foreach ($serialNumberInfo as $serialValue) {
                    $singleSerialInfo = SerialNumberModel::where([
                        'goods_id' => $value['materiel_type_id'],
                        'serial_no' => $serialValue,
                        'delete_flag' => 0
                    ])->first();

                    if (empty($singleSerialInfo)) {
                        throw new Exception('商品:' . $value['materiel_name'] . '序列号:' . $serialValue . '不存在，无法撤销');
                    }

                    $serialData[] = [
                        'goods_id' => $value['materiel_type_id'],
                        'id' => $singleSerialInfo['id'],
                        'status' => 1
                    ];
                }
            }
        }

        if (!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        if (!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        return true;
    }

    //撤销套餐出库
    static public function cancelPackage($data)
    {
        $packageInfo = LogPackageModel::where('id', $data['id'])->first();

        if ($packageInfo['is_cancel'] == 1) {
            return ['code' => 1, 'msg' => '无法重复撤销', 'data' => ""];
        }

        $packageContentInfo = LogPackageContentModel::where('log_package_id', $data['id'])->get()->toArray();
        DB::beginTransaction();

        try {
            foreach ($packageContentInfo as $value) {
                $result = StorageManageModel::where('id', $value['out_storage_manage_id'])->first();

                StorageManageModel::where('id', $value['out_storage_manage_id'])
                    ->update([
                        'in_storage_num' => DB::raw('in_storage_num + ' . $value['operate_num']),
                        'virtual_storage_num' => DB::raw('virtual_storage_num + ' . $value['operate_num']),
                        'delete_flag' => 0
                    ]);

                if ($value['storage_batch_id'] != 0) {
                    StorageBatchModel::where('id', $value['storage_batch_id'])
                        ->increment('batch_left_num', $value['operate_num']);
                }
                if (!empty($value['serial_number'])) {
                    $serialNumberList = explode(',', $value['serial_number']);
                    $scondition['status'] = 0;
                    $scondition['goods_id'] = $value['materiel_type_id'];
                    SerialNumberModel::where($scondition)
                        ->where(['delete_flag' => 0])
                        ->whereIn('serial_no', $serialNumberList)->update(['status' => 1]);
                }
            }

            LogPackageModel::where('id', $data['id'])->update(['is_cancel' => 1]);
            LogOutPackageModel::where(['all_id_type' => 3, 'all_id' => $data['id']])->update(['is_cancel' => 1]);
            $logData = '套餐名称：' . $packageInfo['package_name'] . ',撤销成功！';
            CommonService::operateResult($data['user_id'], $data['logTime'], $data, $logData);
            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ""];
        } catch (Exception $e) {
            DB::rollBack();
            Log::debug('撤销-套餐出库:' . var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    /**
     * 获取旧操作记录列表
     * @param $startTime
     * @param $startTime
     * @param $endTime
     * @param $userType
     * @param $userId
     * @param $mainId
     * @return array
     * @author ソンブ
     * @created_at: 2022/2/9 15:31
     */
    static public function oldLogList($type, $startTime, $endTime, $currPage, $pageSize, $userId, $mainId)
    {
        switch ($type) {
            case 0:
                $result = self::getOldInLog($startTime, $endTime, $currPage, $pageSize, $userId, $mainId);
                break;
            case 1:
                $result = self::getOldOutLog($startTime, $endTime, $currPage, $pageSize, $userId, $mainId);
                break;
        }

        return ['code' => 0, 'msg' => 'success', 'data' => $result];
    }

    static public function getOldInLog($startTime, $endTime, $currPage, $pageSize, $userId, $mainId)
    {
        if ($userId == $mainId) {
            $query = InStorageLogModel::select(
                'a.id',
                'a.type',
                'c.class_name as first_class_name',
                'd.class_name as second_class_name',
                'e.type_name',
                'e.materiel_name',
                'f.storage_name',
                'f.storage_address',
                'a.is_cancel',
                'g.nickname',
                'a.account_type',
                'a.oprate_num',
                'b.in_storage_num',
                'a.oprate_time',
            )
                ->from('in_storage_log as a')
                ->leftJoin('storage_manage as b', 'b.id', '=', 'a.storage_id')
                ->leftJoin('materiel_class as c', 'c.id', '=', 'b.materiel_class_id')
                ->leftJoin('materiel_class as d', 'd.id', '=', 'c.parent_id')
                ->leftJoin('materiel_type as e', 'e.id', '=', 'b.type_id')
                ->leftJoin('storage as f', 'f.id', '=', 'b.storage_id')
                ->leftJoin('admin as g', 'g.id', '=', 'a.main_id')
                ->where('a.main_id', $mainId);
        } else {
            $userInfo = UserModel::where('new_id', $userId)->first();

            $query = InStorageLogModel::select(
                'a.id',
                'a.type',
                'c.class_name as first_class_name',
                'd.class_name as second_class_name',
                'e.type_name',
                'e.materiel_name',
                'f.storage_name',
                'f.storage_address',
                'a.is_cancel',
                'g.nickname',
                'a.account_type',
                'a.oprate_num',
                'b.in_storage_num',
                'a.oprate_time',
            )
                ->from('in_storage_log as a')
                ->leftJoin('storage_manage as b', 'b.id', '=', 'a.storage_id')
                ->leftJoin('materiel_class as c', 'c.id', '=', 'b.materiel_class_id')
                ->leftJoin('materiel_class as d', 'd.id', '=', 'c.parent_id')
                ->leftJoin('materiel_type as e', 'e.id', '=', 'b.type_id')
                ->leftJoin('storage as f', 'f.id', '=', 'b.storage_id')
                ->leftJoin('user as g', 'g.id', '=', 'a.oprater_id')
                ->where('a.oprater_id', $userInfo['id']);
        }

        if (!empty($startTime)) {
            $startTimeArr = explode(' ', $startTime);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($endTime)) {
            $endTimeArr = explode(' ', $endTime);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query = $query->whereBetween('a.oprate_time', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query = $query->where('a.oprate_time', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query = $query->where('a.oprate_time', '<=', $endTime);
        }

        $query = $query->whereIn('type', [0, 1, 6])
            ->orderBy('a.id', 'desc')
            ->paginate($pageSize, ['*'], '', $currPage);

        foreach ($query as $key => $value) {
            $query[$key]['oprate_time'] = date('Y-m-d H:i:s', $value['oprate_time']);
        }

        return $query;
    }

    static public function getOldOutLog($startTime, $endTime, $currPage, $pageSize, $userId, $mainId)
    {
        if ($userId == $mainId) {
            $query = InStorageLogModel::select(
                'a.id',
                'a.type',
                'c.class_name as first_class_name',
                'd.class_name as second_class_name',
                'e.type_name',
                'e.materiel_name',
                'f.storage_name',
                'f.storage_address',
                'a.is_cancel',
                'g.nickname',
                'a.account_type',
                'a.oprate_num',
                'b.in_storage_num',
                'a.oprate_time',
                'h.package_name'
            )
                ->from('in_storage_log as a')
                ->leftJoin('storage_manage as b', 'b.id', '=', 'a.storage_id')
                ->leftJoin('materiel_class as c', 'c.id', '=', 'b.materiel_class_id')
                ->leftJoin('materiel_class as d', 'd.id', '=', 'c.parent_id')
                ->leftJoin('materiel_type as e', 'e.id', '=', 'b.type_id')
                ->leftJoin('storage as f', 'f.id', '=', 'b.storage_id')
                ->leftJoin('admin as g', 'g.id', '=', 'a.main_id')
                ->leftJoin('package as h', 'h.id', '=', 'a.package_id')
                ->where('a.main_id', $mainId);
        } else {
            $userInfo = UserModel::where('new_id', $userId)->first();

            $query = InStorageLogModel::select(
                'a.id',
                'a.type',
                'c.class_name as first_class_name',
                'd.class_name as second_class_name',
                'e.type_name',
                'e.materiel_name',
                'f.storage_name',
                'f.storage_address',
                'a.is_cancel',
                'g.nickname',
                'a.account_type',
                'a.oprate_num',
                'b.in_storage_num',
                'a.oprate_time',
                'h.package_name'
            )
                ->from('in_storage_log as a')
                ->leftJoin('storage_manage as b', 'b.id', '=', 'a.storage_id')
                ->leftJoin('materiel_class as c', 'c.id', '=', 'b.materiel_class_id')
                ->leftJoin('materiel_class as d', 'd.id', '=', 'c.parent_id')
                ->leftJoin('materiel_type as e', 'e.id', '=', 'b.type_id')
                ->leftJoin('storage as f', 'f.id', '=', 'b.storage_id')
                ->leftJoin('user as g', 'g.id', '=', 'a.oprater_id')
                ->leftJoin('package as h', 'h.id', '=', 'a.package_id')
                ->where('a.oprater_id', $userInfo['id']);
        }

        if (!empty($startTime)) {
            $startTimeArr = explode(' ', $startTime);
            $startTime = strtotime($startTimeArr[0] . ' 00:00:00');
        }

        if (!empty($endTime)) {
            $endTimeArr = explode(' ', $endTime);
            $endTime = strtotime($endTimeArr[0] . ' 23:59:59');
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query = $query->whereBetween('a.oprate_time', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query = $query->where('a.oprate_time', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query = $query->where('a.oprate_time', '<=', $endTime);
        }

        $query = $query->whereIn('type', [2, 3])
            ->orderBy('a.id', 'desc')
            ->paginate($pageSize, ['*'], '', $currPage);

        foreach ($query as $key => $value) {
            $query[$key]['package_name'] = empty($value['package_name']) ? '' : $value['package_name'];
            $query[$key]['oprate_time'] = date('Y-m-d H:i:s', $value['oprate_time']);
        }

        return $query;
    }

    static public function cancelOldLog($id, $userId, $mainId)
    {
        $logInfo = InStorageLogModel::where('id', $id)->first();

        if ($logInfo['is_cancel']) {
            return ['code' => 1, 'msg' => '已撤销，无法重复操作', 'data' => ""];
        }

        $storageManageInfo = StorageManageModel::where('id', $logInfo['storage_id'])->where('delete_flag', 0)->first();

        if (empty($storageManageInfo)) {
            return ['code' => 1, 'msg' => '库存信息不存在，无法完成撤销', 'data' => ""];
        }

        //入库撤销
        if (in_array($logInfo['type'], [0, 1, 6])) {
            $result = self::cancelOldIn($logInfo, $storageManageInfo);
        } //出库撤销
        else {
            $result = self::cancelOldOut($logInfo, $storageManageInfo);
        }

        return $result;
    }

    //旧操作记录撤销
    static public function cancelOldIn($logInfo, $storageManageInfo)
    {
        DB::beginTransaction();

        try {
            if ($logInfo['oprate_num'] > $storageManageInfo['in_storage_num']) {
                return ['code' => 1, 'msg' => '库存不足，无法撤销', 'data' => ""];
            }

            if ($logInfo['type'] == 6) {
                StorageManageModel::where('id', $logInfo['before_change_storage'])->increment('in_storage_num', $logInfo['oprate_num'], [
                    'delete_flag' => 0
                ]);
            }

            StorageManageModel::where('id', $storageManageInfo['id'])->decrement('in_storage_num', $logInfo['oprate_num']);
            InStorageLogModel::where('id', $logInfo['id'])->update(['is_cancel' => 1]);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ""];
        } catch (\Exception $e) {
            DB::rollBack();
            Log::debug('旧操作记录入库撤销:' . var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => '撤销失败，请联系管理员', 'data' => ""];
        }
    }

    static public function cancelOldOut($logInfo, $storageManageInfo)
    {
        DB::beginTransaction();

        try {
            StorageManageModel::where('id', $storageManageInfo['id'])->increment('in_storage_num', $logInfo['oprate_num'], [
                'delete_flag' => 0
            ]);
            InStorageLogModel::where('id', $logInfo['id'])->update(['is_cancel' => 1]);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ""];
        } catch (\Exception $e) {
            DB::rollBack();
            Log::debug('旧操作记录出库库撤销:' . var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => '撤销失败，请联系管理员', 'data' => ""];
        }
    }

    public static function inLogExport(array $data, array $user)
    {
        $startTime = empty($data['start_time']) ? '' : strtotime($data['start_time']);
        $endTime = empty($data['end_time']) ? '' : strtotime($data['end_time']);

        return LogInStorageModel::inLogExport($data, $user, $startTime, $endTime);
    }

    public static function outLogExport(array $data, array $user)
    {
        $startTime = empty($data['start_time']) ? '' : strtotime($data['start_time']);
        $endTime = empty($data['end_time']) ? '' : strtotime($data['end_time']);

        return LogOutStorageModel::outLogExport($data, $user, $startTime, $endTime);
    }

    public static function packageOutLogExport($packageId)
    {
        $logData = LogPackageModel::outLogExport($packageId);

        $result = [];
        $materielLine = [];
        foreach ($logData as $key => $value) {
            $materielLine[] = count($value['has_many_content']);
            foreach ($value['has_many_content'] as $val) {
                $result[] = [
                    'package_name' => $value['package_name'],
                    'num' => $value['num'],
                    'nickname' => $value['nickname'],
                    'remark' => empty($value['remark']) ? '' : $value['remark'],
                    'out_storage_time' => $value['out_storage_time'],
                    'created_at' => $value['created_at'],
                    'storage_name' => $val['storage_name'],
                    'storage_address' => $val['storage_address'],
                    'materiel_name' => $val['materiel_name'],
                    'type_name' => $val['type_name'],
                    'materiel_img' => $val['materiel_img'],
                    'operate_num' => $val['operate_num'],
                    'last_storage_num' => $val['last_storage_num'],
                    'next_storage_num' => $val['next_storage_num'],
                    'shelf_name' => $val['shelf_name'],
                    'location_name' => $val['location_name'],
                    'batch_no' => $val['batch_no'],
                ];
            }
        }

        return ['data1' => $result, 'data2' => $materielLine];
    }

    static public function getPackageId($data, $user)
    {
        $startTime = empty($data['start_time']) ? '' : strtotime($data['start_time']);
        $endTime = empty($data['end_time']) ? '' : strtotime($data['end_time']);
        $keyword = empty($data['keyword']) ? '' : $data['keyword'];

        $query = LogPackageModel::select(
            'a.id',
        )
            ->from('log_package as a')
            ->leftJoin('admin as b', 'b.id', '=', 'a.user_id')
            ->leftJoin('log_package_content as c', 'c.log_package_id', '=', 'a.id')
            ->leftJoin('storage_shelf_location as d', 'd.id', '=', 'c.location_id')
            ->leftJoin('storage_shelf as e', 'e.id', '=', 'c.shelf_id')
            ->where('a.delete_flag', 0)
            ->where($user)
            ->where('a.is_cancel', $data['status']);

        if ($data['materiel_class_id'] != 0) {
            $query->where('c.materiel_class_id', $data['materiel_class_id']);
        }

        if (!empty($startTime) && !empty($endTime)) {
            $query->whereBetween('a.created_at', [$startTime, $endTime]);
        } else if (!empty($startTime) && empty($endTime)) {
            $query->where('a.created_at', '>=', $startTime);
        } else if (empty($startTime) && !empty($endTime)) {
            $query->where('a.created_at', '<=', $endTime);
        }

        $query->where(function ($query) use ($keyword) {
            $query->orWhere('package_name', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_name', 'like', '%' . $keyword . '%');
            $query->orWhere('type_name', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_no', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_class_name', 'like', '%' . $keyword . '%');
            $query->orWhere('materiel_class_no', 'like', '%' . $keyword . '%');
        });

        return $query->get()->toArray();
    }

    /**
     * 修改出入库操作数量
     * @param $data
     */
    static public function updOutInStorageNum($data)
    {
        $reqLogInfo = json_decode($data['log_info'], true);
        if (is_array($reqLogInfo)) {
            DB::beginTransaction();
            try {
                $n = 1;
                $param = [
                    'id', 'type', 'upd_num', 'operate_num', 'materiel_name',
                    'materiel_type_id', 'curr_storage_manage_id'
                ];
                if (!empty($data['type'])) {
                    $table = 'log_outstorage';
                    $logFlag = '出库记录';
                } else {
                    $table = 'log_instorage';
                    $logFlag = '入库记录';
                }
                foreach ($reqLogInfo as $val) {
                    $logInfo = DB::table($table)->select($param)
                        ->where([
                            'id' => $val['id'],
                            'delete_flag' => 0,
                            'is_cancel' => 0,
                            'main_id' => $data['main_id']
                        ])->first();
                    if (empty($logInfo)) {
                        throw new \Exception('没有找到,直接出入库操作记录！');
                    }
                    if ($logInfo->type != 2) {
                        throw new \Exception('不是直接出入库记录类型，不能修改操作数量！');
                    }
                    $goodsInfo = MaterielTypeModel::select('is_use_serial')
                        ->where([
                            'id' => $logInfo->materiel_type_id,
                            'main_id' => $data['main_id'],
                            'delete_flag' => 0,
                        ])->first();
                    if (empty($goodsInfo)) {
                        throw new \Exception('商品-' . $logInfo->materiel_name . '没有找到！');
                    }
                    if (!empty($goodsInfo['is_use_serial'])) {
                        throw new \Exception('商品-' . $logInfo->materiel_name . '已开启序列号，不能修改操作数量！');
                    }
                    $query = StorageManageModel::select('in_storage_num')
                        ->where([
                            'id' => $logInfo->curr_storage_manage_id,
                            'main_id' => $data['main_id'],
                            'delete_flag' => 0
                        ]);
                    $industryInfo = $query->first();
                    if (empty($industryInfo)) {
                        throw new \Exception('商品-' . $logInfo->materiel_name . '没找到的库存信息，无法修改！');
                    }
                    if ($val['upd_num'] < 0) {
                        throw new \Exception('商品-' . $logInfo->materiel_name . '，修改数量不能小于0');

                    }
                    if ($val['upd_num'] != $logInfo->operate_num) {
                        DB::table($table)->where('id', $logInfo->id)
                            ->update([
                                //'operate_num' => $val['upd_num'],
                                'last_upd_num' => $logInfo->operate_num,
                                'upd_num' => $logInfo->upd_num + 1
                            ]);

                        $insertData = [];
                        $insertData['last_num'] = $logInfo->operate_num;
                        $insertData['operate_num'] = $val['upd_num'];
                        if (!empty($data['type'])) {
                            $insertData['out_log_id'] = $logInfo->id;
                        } else {
                            $insertData['in_log_id'] = $logInfo->id;
                        }

                        if ($val['upd_num'] > $logInfo->operate_num) {
                            $num = $val['upd_num'] - $logInfo->operate_num;
                            if (!empty($data['type'])) {//修改出库数量大于操作数量，库存减去超出数量
                                $query->decrement('in_storage_num', $num);
                                $insertData['type'] = 1;
                            } else {//修改入库数量大于操作数量，库存加上超出数量
                                $query->increment('in_storage_num', $num);
                                $insertData['type'] = 0;
                            }
                            $insertData['diff_num'] = $num;
                        } elseif ($val['upd_num'] < $logInfo->operate_num) {
                            $num = $logInfo->operate_num - $val['upd_num'];
                            if (!empty($data['type'])) {//修改出库数量小于操作数量，库存加上超出数量
                                $insertData['type'] = 0;
                                $query->increment('in_storage_num', $num);
                            } else {//修改入库数量小于操作数量，库存减去超出数量
                                $insertData['type'] = 1;
                                $query->decrement('in_storage_num', $num);
                            }
                            $insertData['diff_num'] = $num;
                        }

                        UpdInOutLogModel::query()
                            ->insertGetId($insertData);
                    }
                }
                CommonService::operateResult($data['user_id'], $data['logTime'], $data, $logFlag . ',修改成功!');
                DB::commit();
                return success();
            } catch (\Exception $e) {
                DB::rollBack();
                Log::debug('操作记录修改数量异常：' . var_export($e->getMessage(), true));
                return fail('', $e->getMessage());
            }
        } else {
            return fail('', '请求的参数异常！');
        }
    }

    //同条出入库记录
    public static function outInWarehouseLogDetail($data)
    {
        DB::statement(DB::raw('set @row=0'));
        $param = [
            'a.id', 'b.id as goods_id', 'b.materiel_name'/* ,'serial_number' */,
            'b.materiel_no', 'upd_num', 'b.type_name', 'is_use_serial',
            'operate_num', 'last_upd_num', 'is_product_materiel'
        ];
        if (!empty($data['type'])) {
            $model = LogOutStorageModel::select('created_at');
            $query = LogOutStorageModel::select($param)->from('log_outstorage as a');
        } else {
            $model = LogInStorageModel::select('created_at');
            $query = LogInStorageModel::select($param)->from('log_instorage as a');
        }
        $info = $model->where([
            'id' => $data['id'],
            'delete_flag' => 0,
            'main_id' => $data['main_id']
        ])->first();

        $query->selectRaw('@row:=@row+1 as sort_number');
        $query->leftJoin('materiel_type as b', 'b.id', '=', 'a.materiel_type_id')
            ->where([
                'a.created_at' => strtotime($info['created_at']),
                'a.delete_flag' => 0,
                'b.delete_flag' => 0,
                'a.main_id' => $data['main_id']
            ]);
        if (isset($data['is_product'])) {
            $query->where('is_product_materiel', $data['is_product'] ?? 0);
        }
        if (!empty($data['keyword'])) {
            $query->where(function ($query) use ($data) {
                $query->orWhere('b.materiel_name', 'like', '%' . $data['keyword'] . '%');
                $query->orWhere('b.type_name', 'like', '%' . $data['keyword'] . '%');
                $query->orWhere('b.materiel_no', 'like', '%' . $data['keyword'] . '%');
            });
        }
        $list = $query->orderBy('a.created_at', 'desc')
            ->paginate($data['pageSize'], ['*'], '', $data['currentPage'])->toArray();
        if (!empty($list['data'])) {
            foreach ($list['data'] as &$val) {
                $updInLogList = UpdInOutLogModel::query()
                    ->select(
                        "id",
                        "in_log_id",
                        "out_log_id",
                        "operate_num",
                        "last_num",
                        "diff_num",
                        "type"
                    )->where([
                        'in_log_id' => $val['id']
                    ])->get();
                if (!empty($updInLogList)) {
                    foreach ($updInLogList as &$uVal) {
                        if (!empty($uVal['type'])) {
                            $uVal['diff_num'] = '-' . (float)$uVal['diff_num'];
                        } else {
                            $uVal['diff_num'] = '+' . (float)$uVal['diff_num'];
                        }
                    }
                }
                $val['upd_log_list'] = $updInLogList ?? [];
            }
        }

        return $list;
    }
}
